pax_global_header00006660000000000000000000000064141620101400014477gustar00rootroot0000000000000052 comment=d3873c0693fe08e6233177c2f342af62547dcaa6 yapf-0.32.0/000077500000000000000000000000001416201014000125205ustar00rootroot00000000000000yapf-0.32.0/.coveragerc000066400000000000000000000001251416201014000146370ustar00rootroot00000000000000[report] # Verifier is used for testing only. omit = */__main__.py */verifier.py yapf-0.32.0/.editorconfig000066400000000000000000000004111416201014000151710ustar00rootroot00000000000000# EditorConfig is awesome: http://EditorConfig.org # top-most EditorConfig file root = true # Unix-style newlines with a newline ending every file [*] end_of_line = lf insert_final_newline = true # 2 space indentation [*.py] indent_style = space indent_size = 2 yapf-0.32.0/.flake8000066400000000000000000000006461416201014000137010ustar00rootroot00000000000000[flake8] ignore = # 'toml' imported but unused F401, # 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 disable-noqa indent-size = 2 max-line-length = 80 yapf-0.32.0/.github/000077500000000000000000000000001416201014000140605ustar00rootroot00000000000000yapf-0.32.0/.github/workflows/000077500000000000000000000000001416201014000161155ustar00rootroot00000000000000yapf-0.32.0/.github/workflows/ci.yml000066400000000000000000000016431416201014000172370ustar00rootroot00000000000000# 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] 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 yapf-0.32.0/.gitignore000066400000000000000000000022741416201014000145150ustar00rootroot00000000000000#==============================================================================# # This file specifies intentionally untracked files that git should ignore. # See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html # # This file is intentionally different from the output of `git svn show-ignore`, # as most of those are useless. #==============================================================================# #==============================================================================# # File extensions to be ignored anywhere in the tree. #==============================================================================# # Temp files created by most text editors. *~ # Merge files created by git. *.orig # Byte compiled python modules. *.pyc # vim swap files .*.sw? .sw? # OS X specific files. .DS_store #==============================================================================# # Files to ignore #==============================================================================# /.coverage # Directories to ignore (do not add trailing '/'s, they skip symlinks). #==============================================================================# /build /dist /.tox /yapf.egg-info /.idea yapf-0.32.0/.pre-commit-config.yaml000066400000000000000000000014431416201014000170030ustar00rootroot00000000000000# 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 yapf-0.32.0/.pre-commit-config.yml000066400000000000000000000014431416201014000166420ustar00rootroot00000000000000# 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 yapf-0.32.0/.pre-commit-hooks.yaml000066400000000000000000000003571416201014000166640ustar00rootroot00000000000000# 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] yapf-0.32.0/.pre-commit-hooks.yml000066400000000000000000000003571416201014000165230ustar00rootroot00000000000000# 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] yapf-0.32.0/.style.yapf000066400000000000000000000000361416201014000146160ustar00rootroot00000000000000[style] based_on_style = yapf yapf-0.32.0/.vimrc000066400000000000000000000002471416201014000136440ustar00rootroot00000000000000" Force indentation styles for this directory autocmd FileType python set shiftwidth=2 autocmd FileType python set tabstop=2 autocmd FileType python set softtabstop=2 yapf-0.32.0/AUTHORS000066400000000000000000000004631416201014000135730ustar00rootroot00000000000000# This is the official list of YAPF authors for copyright purposes. # This file is distinct from the CONTRIBUTORS files. # See the latter for an explanation. # Names should be added to this file as: # Name or Organization # The email address is not required for organizations. Google Inc. yapf-0.32.0/CHANGELOG000066400000000000000000001043631416201014000137410ustar00rootroot00000000000000# Change Log # All notable changes to this project will be documented in this file. # This project adheres to [Semantic Versioning](http://semver.org/). ## [0.32.0] 2021-12-26 ### 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. - Add CI via GitHub Actions. ### Changes - 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. - 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 prescribed by PEP8. - Fixed the '...' token to be spaced after a colon. ## [0.31.0] 2021-03-14 ### 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. - 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 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 - Exclude directories on Windows. ## [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- 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. ### 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 `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. - Don't split between two-word comparison operators: "is not", "not in", etc. ## [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. - 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 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. - 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. - 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. - 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 - 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 fits in its starting line, then the subexpression is not split (thus avoiding 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. - 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. - 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 - `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. - 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. - 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. - 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. - 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 - `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 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. - 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. - 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. - 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. - 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 - 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 opening bracket with `DEDENT_CLOSING_BRACKETS` enabled. ## [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, 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 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. - 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. - 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 - `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. - 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. - 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 - 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 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! - 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. - 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 - 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. - 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. ## [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 ### 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 account and don't split after the unpacking operator. ## [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 - 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. - 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 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. - 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 - 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. ### 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. - 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. - 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 - 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 - 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. - 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. - Increase indent for continuation line with same indent as next logical line with 'async with' statement. ## [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. ### 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. - 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 - 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 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. - 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. - 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. - Changed coalesce brackets not to line split before closing bracket. ## [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. - 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 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. - Ensure tabs are used for continued indentation when USE_TABS is True. ## [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 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. - 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. - 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 - 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)) - 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 - 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 - Keep type annotations intact as much as possible. Don't try to split the over 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 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 - 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 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. - 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 - 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. ## [0.13.0] 2016-10-16 ### 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 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. - 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 - 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. - 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. 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 - 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. - 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. - Don't count the argument list of a lambda as a named assign in a function call. ## [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 colon. - 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. - 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. ## [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 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 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. - 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 - The COALESCE_BRACKETS knob prevents splitting consecutive brackets when DEDENT_CLOSING_BRACKETS is set. - Don't count "pylint" directives as exceeding the column limit. ### Changed - We split all of the arguments to a function call if there's a named argument. In this case, we want to split after the opening bracket too. This makes things look a bit better. ### Fixed - When retaining format of a multiline string with Chromium style, make sure that the multiline string doesn't mess up where the following comma ends up. - Correct for when 'lib2to3' smooshes comments together into the same DEDENT node. ## [0.10.0] 2016-06-14 ### Added - Add a knob, 'USE_TABS', to allow using tabs for indentation. ### Changed - Performance enhancements. ### Fixed - Don't split an import list if it's not surrounded by parentheses. ## [0.9.0] 2016-05-29 ### Added - Added a knob (SPLIT_PENALTY_BEFORE_IF_EXPR) to adjust the split penalty before an if expression. This allows the user to place a list comprehension all on one line. - Added a knob (SPLIT_BEFORE_FIRST_ARGUMENT) that encourages splitting before the first element of a list of arguments or parameters if they are going to be split anyway. - Added a knob (SPLIT_ARGUMENTS_WHEN_COMMA_TERMINATED) splits arguments to a function if the list is terminated by a comma. ### Fixed - Don't split before a first element list argument as we would before a first element function call. - Don't penalize when we must split a line. - Allow splitting before the single argument in a function call. ## [0.8.2] 2016-05-21 ### Fixed - Prefer not to split after the opening of a subscript. - Don't add space before the 'await' keyword if it's preceded by an opening paren. - When we're setting the split penalty for a continuous list, we don't want to mistake a comment at the end of that list as part of the list. - When calculating blank lines, don't assume the last seen object was a class or function when we're in a class or function. - Don't count the closing scope when determining if the current scope is the last scope on the line. ## [0.8.1] 2016-05-18 ### Fixed - 'SPLIT_BEFORE_LOGICAL_OPERATOR' wasn't working correctly. The penalty was being set incorrectly when it was part of a larger construct. - Don't separate a keyword, like "await", from a left paren. - Don't rely upon the original tokens' line number to determine if we should perform splitting in Facebook mode. The line number isn't the line number of the reformatted token, but the line number where it was in the original code. Instead, we need to carefully determine if the line is liabel to be split and act accordingly. ## [0.8.0] 2016-05-10 ### Added - Add a knob, 'SPACES_AROUND_POWER_OPERATOR', to allow adding spaces around the power operator. ### Fixed - There shouldn't be a space between a decorator and an intervening comment. - If we split before a bitwise operator, then we assume that the programmer knows what they're doing, more or less, and so we enforce a split before said operator if one exists in the original program. - Strengthen the bond between a keyword and value argument. - Don't add a blank line after a multiline string. - If the "for" part of a list comprehension can exist on the starting line without going over the column limit, then let it remain there. ## [0.7.1] 2016-04-21 ### Fixed - Don't rewrite the file if there are no changes. - Ensure the proper number of blank lines before an async function. - Split after a bitwise operator when in PEP 8 mode. - Retain the splitting within a dictionary data literal between the key and value. - Try to keep short function calls all on one line even if they're part of a larger series of tokens. This stops us from splitting too much. ## [0.7.0] 2016-04-09 ### Added - Support for Python 3.5. - Add 'ALLOW_MULTILINE_LAMBDAS' which allows lambdas to be formatted onto multiple lines. ### Fixed - Lessen penalty for splitting before a dictionary keyword. - Formatting of trailing comments on disabled formatting lines. - Disable / enable formatting at end of multi-line comment. ## [0.6.3] 2016-03-06 ### Changed - Documentation updated. ### Fixed - Fix spacing of multiline comments when formatting is disabled. ## [0.6.2] 2015-11-01 ### Changed - Look at the 'setup.cfg' file to see if it contains style information for YAPF. - Look at the '~/.config/yapf/style' file to see if it contains global style information for YAPF. ### Fixed - Make lists that can fit on one line more likely to stay together. - Correct formatting of '*args' and '**kwargs' when there are default values in the argument list. ## [0.6.1] 2015-10-24 ### Fixed - Make sure to align comments in data literals correctly. Also make sure we don't count a "#." in a string as an i18n comment. - 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 "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. - Increase the penalty for splitting after a pseudo-paren. This could lead to less readable code in some circumstances. ## [0.6.0] 2015-10-18 ### Added - Add knob to indent the dictionary value if there is a split before it. ### Changed - No longer check that a file is a "Python" file unless the '--recursive' flag is specified. - No longer allow the user to specify a directory unless the '--recursive' flag is specified. ### Fixed - When determining if we should split a dictionary's value to a new line, use the longest entry instead of the total dictionary's length. This allows the formatter to reformat the dictionary in a more consistent manner. - Improve how list comprehensions are formatted. Make splitting dependent upon whether the "comp_for" or "comp_if" goes over the column limit. - Don't over indent if expression hanging indents if we expect to dedent the closing bracket. - 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 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. - Remove spaces around '**' operator. - Retain formatting of comments in the middle of an expression. - Don't add a newline to an empty file. - Over indent a function's parameter list if it's not distinguished from the body of the function. ## [0.5.0] 2015-10-11 ### Added - Add option to exclude files/directories from formatting. - Add a knob to control whether import names are split after the first '('. ### Fixed - Indent the continuation of an if-then statement when it's not distinguished from the body of the if-then. - Allow for sensible splitting of array indices where appropriate. - Prefer to not split before the ending bracket of an atom. This produces better code in most cases. - Corrected how horizontal spaces were presevered in a disabled region. ## [0.4.0] 2015-10-07 ### Added - Support for dedenting closing brackets, "facebook" style. ### Fixed - Formatting of tokens after a multiline string didn't retain their horizontal spacing. ## [0.3.1] 2015-09-30 ### Fixed - Format closing scope bracket correctly when indentation size changes. ## [0.3.0] 2015-09-20 ### Added - Return a 2 if the source changed, 1 on error, and 0 for no change. ### Fixed - Make sure we format if the "lines" specified are in the middle of a statement. ## [0.2.9] - 2015-09-13 ### Fixed - Formatting of multiple files. It was halting after formatting the first file. ## [0.2.8] - 2015-09-12 ### Added - Return a non-zero exit code if the source was changed. - Add bitwise operator splitting penalty and prefer to split before bitwise operators. ### Fixed - Retain vertical spacing between disabled and enabled lines. - Split only at start of named assign. - Retain comment position when formatting is disabled. - Honor splitting before or after logical ops. yapf-0.32.0/CONTRIBUTING.rst000066400000000000000000000034651416201014000151710ustar00rootroot00000000000000Want to contribute? Great! First, read this page (including the small print at the end). Before you contribute --------------------- 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 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 know that your code infringes on other people's patents. You don't have to sign the CLA until after you've submitted your code for review and a member has approved it, but you must do it before we can put your code into our codebase. Before you start working on a larger contribution, you should get in touch with 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 ------------ All submissions, including submissions by project members, require review. We use Github pull requests for this purpose. YAPF coding style ----------------- 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. 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 ----------- Contributions made by corporations are covered by a different agreement than the one above, the Software Grant and Corporate Contributor License Agreement. yapf-0.32.0/CONTRIBUTORS000066400000000000000000000012011416201014000143720ustar00rootroot00000000000000# People who have agreed to one of the CLAs and can contribute patches. # The AUTHORS file lists the copyright holders; this file # lists people. For example, Google employees are listed here # but not in AUTHORS, because Google holds the copyright. # # https://developers.google.com/open-source/cla/individual # https://developers.google.com/open-source/cla/corporate # # Names should be added to this file as: # Name Bill Wendling Eli Bendersky Sam Clegg Łukasz Langa Oleg Butuzov Mauricio Herrera Cuadra yapf-0.32.0/HACKING.rst000066400000000000000000000015701416201014000143210ustar00rootroot00000000000000Running 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 Python 2.7 and 3.6] * Bump version in yapf/__init__.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. yapf-0.32.0/LICENSE000066400000000000000000000261361416201014000135350ustar00rootroot00000000000000 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. yapf-0.32.0/MANIFEST.in000066400000000000000000000004031416201014000142530ustar00rootroot00000000000000include 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 yapf-0.32.0/README.rst000066400000000000000000001016121416201014000142100ustar00rootroot00000000000000==== 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 :alt: Build status .. 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 (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. 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 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 under Python 3 (and similarly for Python 2). Usage ===== 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. positional arguments: files optional arguments: -h, --help show this help message and exit -v, --version show version number and exit -d, --diff print the diff for the fixed source -i, --in-place make changes to files in place -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. Requires concurrent.futures in Python 2.X -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_pattens`` 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 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: 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! yapf-0.32.0/plugins/000077500000000000000000000000001416201014000142015ustar00rootroot00000000000000yapf-0.32.0/plugins/README.rst000066400000000000000000000056521416201014000157000ustar00rootroot00000000000000=========== 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``. yapf-0.32.0/plugins/pre-commit.sh000077500000000000000000000053401416201014000166160ustar00rootroot00000000000000#!/usr/bin/env 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=() 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 ########## PIP VERSION ############# # Verify that yapf is installed; if not, warn and exit. if ! command -v yapf >/dev/null; 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 ! 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 # fi ###### END PIPENV VERSION ########## # Check for unstaged changes to files in the index. 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.' echo 'Files with unstaged changes:' "${CHANGED_FILES[@]}" 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=() 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 else exit 0 fi yapf-0.32.0/plugins/vim/000077500000000000000000000000001416201014000147745ustar00rootroot00000000000000yapf-0.32.0/plugins/vim/autoload/000077500000000000000000000000001416201014000166045ustar00rootroot00000000000000yapf-0.32.0/plugins/vim/autoload/yapf.vim000066400000000000000000000032111416201014000202550ustar00rootroot00000000000000" 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 Autoload script for YAPF support " " Place this script in your ~/.vim/autoload directory. You can add accessors to " ~/.vimrc, e.g.: " " map :call yapf#YAPF() " imap :call yapf#YAPF() " function! yapf#YAPF() range " Determine range to format. let l:line_ranges = a:firstline . '-' . a:lastline let l:cmd = 'yapf --lines=' . l:line_ranges " Call YAPF with the current buffer 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 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) " Reset cursor to first line of the formatted range. call cursor(a:firstline, 1) endfunction yapf-0.32.0/plugins/vim/plugin/000077500000000000000000000000001416201014000162725ustar00rootroot00000000000000yapf-0.32.0/plugins/vim/plugin/yapf.vim000066400000000000000000000017731416201014000177560ustar00rootroot00000000000000" 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() yapf-0.32.0/pylintrc000066400000000000000000000315211416201014000143110ustar00rootroot00000000000000[MASTER] # Specify a configuration file. #rcfile= # Python code to execute, usually for sys.path manipulation such as # pygtk.require(). #init-hook= # Add files or directories to the blacklist. They should be base names, not # paths. ignore=CVS # Pickle collected data for later comparisons. persistent=yes # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. load-plugins= # Use multiple processes to speed up Pylint. jobs=1 # Allow loading of arbitrary C extensions. Extensions are imported into the # active Python interpreter and may run arbitrary code. unsafe-load-any-extension=no # A comma-separated list of package or module names from where C extensions may # be loaded. Extensions are loading into the active Python interpreter and may # run arbitrary code extension-pkg-whitelist= # Allow optimization of some AST trees. This will activate a peephole AST # optimizer, which will apply various small optimizations. For instance, it can # be used to obtain the result of joining multiple strings with the addition # operator. Joining a lot of strings can lead to a maximum recursion error in # Pylint and this flag can prevent that. It has one side effect, the resulting # AST will be different than the one from reality. optimize-ast=no [MESSAGES CONTROL] # Only show warnings with the listed confidence levels. Leave empty to show # all. Valid levels: HIGH, INFERENCE, INFERENCE_FAILURE, UNDEFINED confidence= # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option # multiple time (only on the command line, not in the configuration file where # it should appear only once). See also the "--disable" option for examples. #enable= # Disable the message, report, category or checker with the given id(s). You # 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 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 # --disable=W" disable= # disabled by me, locally-disabled, missing-docstring, fixme, # disabled by default, import-star-module-level, old-octal-literal, oct-method, print-statement, unpacking-in-except, parameter-unpacking, backtick, old-raise-syntax, old-ne-operator, long-suffix, dict-view-method, dict-iter-method, metaclass-assignment, next-method-called, raising-string, indexing-exception, raw_input-builtin, long-builtin, file-builtin, execfile-builtin, coerce-builtin, cmp-builtin, buffer-builtin, basestring-builtin, apply-builtin, filter-builtin-not-iterating, using-cmp-argument, useless-suppression, range-builtin-not-iterating, suppressed-message, no-absolute-import, old-division, cmp-method, reload-builtin, zip-builtin-not-iterating, intern-builtin, unichr-builtin, reduce-builtin, standarderror-builtin, unicode-builtin, xrange-builtin, coerce-method, delslice-method, getslice-method, setslice-method, input-builtin, round-builtin, hex-method, nonzero-method, map-builtin-not-iterating, [REPORTS] # Set the output format. Available formats are text, parseable, colorized, msvs # (visual studio) and html. You can also give a reporter class, eg # mypackage.mymodule.MyReporterClass. output-format=text # Put messages in a separate file for each module / package specified on the # command line instead of printing them on stdout. Reports (if any) will be # written in a file name "pylint_global.[txt|html]". files-output=no # Tells whether to display a full report or only the messages reports=yes # Python expression which should return a note less than 10 (10 is the highest # note). You have access to the variables errors warning, statement which # respectively contain the number of errors / warnings messages and the total # number of statements analyzed. This is used by the global evaluation report # (RP0004). evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) # Template used to display messages. This is a python new-style format string # used to format the message information. See doc for all details #msg-template= [FORMAT] # Maximum number of characters on a single line. max-line-length=100 # Regexp for a line that is allowed to be longer than the limit. ignore-long-lines=^\s*(# )??$ # Allow the body of an if to be on the same line as the test if there is no # else. single-line-if-stmt=no # List of optional constructs for which whitespace checking is disabled. `dict- # separator` is used to allow tabulation in dicts, etc.: {1 : 1,\n222: 2}. # `trailing-comma` allows a space between comma and closing bracket: (a, ). # `empty-line` allows space-only lines. no-space-check=trailing-comma,dict-separator # Maximum number of lines in a module max-module-lines=1000 # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 # tab). indent-string=' ' # Number of spaces of indent required inside a hanging or continued line. indent-after-paren=4 # Expected format of line ending, e.g. empty (any line ending), LF or CRLF. expected-line-ending-format= [SPELLING] # Spelling dictionary name. Available dictionaries: none. To make it working # install python-enchant package. spelling-dict= # List of comma separated words that should not be checked. spelling-ignore-words= # A path to a file that contains private dictionary; one word per line. spelling-private-dict-file= # Tells whether to store unknown words to indicated private dictionary in # --spelling-private-dict-file option instead of raising a message. spelling-store-unknown-words=no [LOGGING] # Logging modules to check that the string format arguments are in logging # function parameter format logging-modules=logging [BASIC] # List of builtins function names that should not be used, separated by a comma bad-functions=map,filter,input # Good variable names which should always be accepted, separated by a comma good-names=i,e,s,_,fd,fp # Bad variable names which should always be refused, separated by a comma bad-names=foo,bar,baz,toto,tutu,tata # Colon-delimited sets of names that determine each other's naming style when # the name regexes allow several styles. name-group= # Include a hint for the correct naming format with invalid-name include-naming-hint=no # Regular expression matching correct function names # original: #function-rgx=[a-z_][a-z0-9_]{2,30}$ function-rgx=[a-zA-Z_][a-zA-Z0-9_]{2,40}$ # Naming hint for function names function-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct variable names variable-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for variable names variable-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct constant names # original: #const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ const-rgx=(([a-zA-Z_][a-zA-Z0-9_]*)|(__.*__))$ # Naming hint for constant names const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ # Regular expression matching correct attribute names attr-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for attribute names attr-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct argument names argument-rgx=[a-z_][a-z0-9_]{2,30}$ # Naming hint for argument names argument-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression matching correct class attribute names # original: #class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,40}|(__.*__))$ # Naming hint for class attribute names class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ # Regular expression matching correct inline iteration names inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ # Naming hint for inline iteration names inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ # Regular expression matching correct class names # original: #class-rgx=[A-Z_][a-zA-Z0-9]+$ class-rgx=[a-zA-Z_][a-zA-Z0-9]+$ # Naming hint for class names class-name-hint=[A-Z_][a-zA-Z0-9]+$ # Regular expression matching correct module names module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Naming hint for module names module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ # Regular expression matching correct method names # original: #method-rgx=[a-z_][a-z0-9_]{2,30}$ method-rgx=[a-zA-Z_][a-zA-Z0-9_]{2,40}$ # Naming hint for method names method-name-hint=[a-z_][a-z0-9_]{2,30}$ # Regular expression which should only match function or class names that do # not require a docstring. no-docstring-rgx=^_ # Minimum line length for functions/classes that require docstrings, shorter # ones are exempt. docstring-min-length=-1 [ELIF] # Maximum number of nested blocks for function / method body max-nested-blocks=5 [SIMILARITIES] # Minimum lines number of a similarity. min-similarity-lines=4 # Ignore comments when computing similarities. ignore-comments=yes # Ignore docstrings when computing similarities. ignore-docstrings=yes # Ignore imports when computing similarities. ignore-imports=no [TYPECHECK] # Tells whether missing members accessed in mixin class should be ignored. A # mixin class is detected if its name ends with "mixin" (case insensitive). ignore-mixin-members=yes # List of module names for which member attributes should not be checked # (useful for modules/projects where namespaces are manipulated during runtime # and thus existing member attributes cannot be deduced by static analysis. It # supports qualified module names, as well as Unix pattern matching. ignored-modules= # List of classes names for which member attributes should not be checked # (useful for classes with attributes dynamically set). This supports can work # with qualified names. ignored-classes= # List of members which are set dynamically and missed by pylint inference # system, and so shouldn't trigger E1101 when accessed. Python regular # expressions are accepted. generated-members= [MISCELLANEOUS] # List of note tags to take in consideration, separated by a comma. notes=FIXME,XXX,TODO [VARIABLES] # Tells whether we should check for unused import in __init__ files. init-import=no # A regular expression matching the name of dummy variables (i.e. expectedly # not used). dummy-variables-rgx=_$|dummy # List of additional names supposed to be defined in builtins. Remember that # you should avoid to define new builtins when possible. additional-builtins= # List of strings which can identify a callback function by name. A callback # name must start or end with one of those strings. callbacks=cb_,_cb [CLASSES] # List of method names used to declare (i.e. assign) instance attributes. defining-attr-methods=__init__,__new__,setUp # List of valid names for the first argument in a class method. valid-classmethod-first-arg=cls # List of valid names for the first argument in a metaclass class method. valid-metaclass-classmethod-first-arg=mcs # List of member names, which should be excluded from the protected access # warning. exclude-protected=_asdict,_fields,_replace,_source,_make [DESIGN] # Maximum number of arguments for function / method max-args=5 # Argument names that match this expression will be ignored. Default to name # with leading underscore ignored-argument-names=_.* # Maximum number of locals for function / method body max-locals=15 # Maximum number of return / yield for function / method body max-returns=6 # Maximum number of branch for function / method body max-branches=12 # Maximum number of statements in function / method body max-statements=50 # Maximum number of parents for a class (see R0901). max-parents=7 # Maximum number of attributes for a class (see R0902). max-attributes=7 # Minimum number of public methods for a class (see R0903). min-public-methods=2 # Maximum number of public methods for a class (see R0904). max-public-methods=20 # Maximum number of boolean expressions in a if statement max-bool-expr=5 [IMPORTS] # Deprecated modules which should not be used, separated by a comma deprecated-modules=regsub,TERMIOS,Bastion,rexec # Create a graph of every (i.e. internal and external) dependencies in the # given file (report RP0402 must not be disabled) import-graph= # Create a graph of external dependencies in the given file (report RP0402 must # not be disabled) ext-import-graph= # Create a graph of internal dependencies in the given file (report RP0402 must # not be disabled) int-import-graph= [EXCEPTIONS] # Exceptions that will emit a warning when being caught. Defaults to # "Exception" overgeneral-exceptions=Exception yapf-0.32.0/setup.cfg000066400000000000000000000000341416201014000143360ustar00rootroot00000000000000[bdist_wheel] universal = 1 yapf-0.32.0/setup.py000066400000000000000000000045171416201014000142410ustar00rootroot00000000000000#!/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 find_packages, setup, Command import yapf 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.rst', 'r', 'utf-8') as fd: setup( name='yapf', version=yapf.__version__, description='A formatter for Python code.', long_description=fd.read(), license='Apache License, Version 2.0', author='Google Inc.', maintainer='Bill Wendling', maintainer_email='morbo@google.com', packages=find_packages('.'), 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 :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.6', '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, }, ) yapf-0.32.0/tox.ini000066400000000000000000000001321416201014000140270ustar00rootroot00000000000000[tox] envlist=py27,py34,py35,py36,py37,py38 [testenv] commands= python setup.py test yapf-0.32.0/yapf/000077500000000000000000000000001416201014000134575ustar00rootroot00000000000000yapf-0.32.0/yapf/__init__.py000066400000000000000000000303631416201014000155750ustar00rootroot00000000000000# 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. """YAPF. YAPF uses the algorithm in clang-format to figure out the "best" formatting for Python code. It looks at the program as a series of "unwrappable lines" --- i.e., lines which, if there were no column limit, we would place all tokens on 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 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. If no filenames are specified, YAPF reads the code from stdin. """ from __future__ import print_function import argparse 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.32.0' def main(argv): """Main program. Arguments: argv: command-line arguments, such as sys.argv (including the program name in argv[0]). Returns: 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. """ 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. 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. This argument overrides the 'args.lines'. It can be used by third-party code (e.g., IDEs) when reformatting a snippet of code. style_config: (string) Style name or file path. no_local_style: (string) If style_config is None don't search for directory-local style configuration. 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. 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( 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 range like 'start-end'. Returns: A list of tuples of the start and end line numbers. 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 def _BuildParser(): """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) if __name__ == '__main__': run_main() yapf-0.32.0/yapf/__main__.py000066400000000000000000000012501416201014000155470ustar00rootroot00000000000000# 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. """Main entry point.""" # pylint: disable=invalid-name import yapf yapf.run_main() yapf-0.32.0/yapf/third_party/000077500000000000000000000000001416201014000160105ustar00rootroot00000000000000yapf-0.32.0/yapf/third_party/__init__.py000066400000000000000000000000001416201014000201070ustar00rootroot00000000000000yapf-0.32.0/yapf/third_party/yapf_diff/000077500000000000000000000000001416201014000177375ustar00rootroot00000000000000yapf-0.32.0/yapf/third_party/yapf_diff/LICENSE000066400000000000000000000277471416201014000207650ustar00rootroot00000000000000 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. yapf-0.32.0/yapf/third_party/yapf_diff/__init__.py000066400000000000000000000000001416201014000220360ustar00rootroot00000000000000yapf-0.32.0/yapf/third_party/yapf_diff/yapf_diff.py000066400000000000000000000113001416201014000222330ustar00rootroot00000000000000# 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 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)]) # 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() yapf-0.32.0/yapf/yapflib/000077500000000000000000000000001416201014000151055ustar00rootroot00000000000000yapf-0.32.0/yapf/yapflib/__init__.py000066400000000000000000000011241416201014000172140ustar00rootroot00000000000000# 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. yapf-0.32.0/yapf/yapflib/blank_line_calculator.py000066400000000000000000000142771416201014000220010ustar00rootroot00000000000000# 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. """Calculate the number of blank lines between top-level entities. Calculates how many blank lines we need between classes, functions, and other entities at the same level. CalculateBlankLines(): the main function exported by this module. Annotations: 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 from yapf.yapflib import style _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' }) 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. This will set the blank lines required if the last entity was a class or function. 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) 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. Arguments: node: (pytree.Node) The classdef or funcdef 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) yapf-0.32.0/yapf/yapflib/comment_splicer.py000066400000000000000000000356261416201014000206560ustar00rootroot00000000000000# 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. """Comment splicer for lib2to3 trees. The lib2to3 syntax tree produced by the parser holds comments and whitespace in prefix attributes of nodes, rather than nodes themselves. This module provides functionality to splice comments out of prefixes and into nodes of their own, making them easier to process. SpliceComments(): the main function exported by this module. """ from lib2to3 import pygram from lib2to3 import pytree from lib2to3.pgen2 import token from yapf.yapflib import pytree_utils 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. Args: 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. Args: comment_prefix: (unicode) the text of the comment from the node's prefix. comment_lineno: (int) the line number for the start of the comment. comment_column: (int) the column for the start of the comment. standalone: (bool) determines if the comment is standalone or not. Returns: The simple_stmt nodes if this is a standalone comment, otherwise a list of 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 # "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 # standalone line nodes in the grammar. It is meant to be exhaustive # *eventually*, and we'll modify it with time as we discover more corner cases # in the parse tree. # # 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 "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' ]) def _FindNodeWithStandaloneLineParent(node): """Find a node whose parent is a 'standalone line' node. See the comment above _STANDALONE_LINE_NODES for more details. Arguments: node: node to start from 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) # "Statement nodes" are standalone statements. The don't have to start a new # line. _STATEMENT_NODES = frozenset(['simple_stmt']) | _STANDALONE_LINE_NODES def _FindStmtParent(node): """Find the nearest parent of node that is a statement node. Arguments: node: node to start from Returns: Nearest parent (or node itself, if suitable). """ 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. Arguments: node: node to start from. This must not be the tree root. indent: indentation string for the ancestor we're looking for. See _AnnotateIndents for more details. Returns: 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. 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. Arguments: tree: root of a pytree. The pytree is modified to add annotations to nodes. 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) yapf-0.32.0/yapf/yapflib/continuation_splicer.py000066400000000000000000000033601416201014000217140ustar00rootroot00000000000000# 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. """Insert "continuation" nodes into lib2to3 tree. 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 function exported by this module. """ from lib2to3 import pytree from yapf.yapflib import format_token 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) yapf-0.32.0/yapf/yapflib/errors.py000066400000000000000000000027121416201014000167750ustar00rootroot00000000000000# 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. """YAPF error objects.""" from lib2to3.pgen2 import tokenize 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. """ 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. Exceptions of this type are handled by the command line tool and result in clear error messages, as opposed to backtraces. """ pass yapf-0.32.0/yapf/yapflib/file_resources.py000066400000000000000000000226451416201014000205010ustar00rootroot00000000000000# 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. """Interface to file resources. This module provides functions for interfacing with files: opening, writing, and querying. """ import fnmatch import os import re from lib2to3.pgen2 import tokenize from yapf.yapflib import errors from yapf.yapflib import py3compat from yapf.yapflib import style 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()) if any(e.startswith('./') for e in ignore_patterns): raise errors.YapfError('path in .yapfignore should not start with ./') 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") 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 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, otherwise empty List. """ 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): """Return default style name for a given directory. Looks for .style.yapf or setup.cfg or pyproject.toml 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 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: 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 dirname = os.path.dirname(dirname) global_file = os.path.expanduser(style.GLOBAL_STYLE) if os.path.exists(global_file): return global_file 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 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. Arguments: filename: (unicode) The name of the unformatted file. reformatted_code: (unicode) The reformatted code. 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): 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 = tokenize.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 tokenize.detect_encoding(fd.readline)[0] yapf-0.32.0/yapf/yapflib/format_decision_state.py000066400000000000000000001355631416201014000220410ustar00rootroot00000000000000# 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. """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, 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 each decision needs to be its own unique copy. Once the heuristic determines the best formatting, it makes a non-dry run pass through the code to commit the whitespace formatting. 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 from yapf.yapflib import style from yapf.yapflib import subtypes class FormatDecisionState(object): """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 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. 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. 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. column_limit: The column limit specified by the style. """ def __init__(self, line, first_indent): """Initializer. Initializes to the state after placing the first token from 'line' at 'first_indent'. Arguments: 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. 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 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 # 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 == ',': 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 (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 # 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 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. Arguments: newline: (bool) Add the token on a new line if True. dry_run: (bool) Don't commit whitespace changes to the FormatToken if True. must_split: (bool) A newline was required before this token. Returns: The penalty of splitting after the current token. """ self._PushParameterListState(newline) penalty = 0 if newline: penalty = self._AddTokenOnNewline(dry_run, must_split) else: self._AddTokenOnCurrentLine(dry_run) penalty += self._CalculateComprehensionState(newline) penalty += self._CalculateParameterListState(newline) return self.MoveStateToNextToken() + penalty 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. 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. Appends the next token to the state and updates information necessary for indentation. Arguments: dry_run: (bool) Don't commit whitespace changes to the FormatToken if True. must_split: (bool) A newline was required before this token. 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. 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(): 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. 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 += 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 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 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'))): 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 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'}) 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 _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 _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 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 _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 _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. A stack of _ParenState objects are kept so that we know how to indent relative to the brackets. Attributes: 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. num_line_splits: Number of line splits this _ParenState contains already. 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)) yapf-0.32.0/yapf/yapflib/format_token.py000066400000000000000000000251731416201014000201570ustar00rootroot00000000000000# 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. """Pytree nodes with extra formatting information. This is a thin wrapper around a pytree.Leaf node. """ import keyword import re from lib2to3.pgen2 import token 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 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. 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 class FormatToken(object): """A wrapper around pytree Leaf nodes. This represents the token plus additional information useful for reformatting the code. Attributes: node: The PyTree node this token represents. 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 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 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 instance, a comment may have n required spaces before it. But the 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 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. 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): """Constructor. Arguments: node: (pytree.Leaf) The node that's being wrapped. """ self.node = 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 = '' 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.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: 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 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. Arguments: newlines_before: (int) The number of newlines to place before the token. 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.node.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 pytree_utils.OPENING_BRACKETS 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( '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) yapf-0.32.0/yapf/yapflib/identify_container.py000066400000000000000000000044151416201014000213400ustar00rootroot00000000000000# 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.pgen2 import token as grammar_token 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 for child in node.children: self.Visit(child) 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]) 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 for child in node.children[1].children: pytree_utils.SetOpeningBracket( pytree_utils.FirstLeafNode(child), node.children[0]) yapf-0.32.0/yapf/yapflib/line_joiner.py000066400000000000000000000075141416201014000177630ustar00rootroot00000000000000# 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. """Join logical lines together. Determine how many lines can be joined into one line. For instance, we could join these statements into one line: if a == 42: continue like this: if a == 42: continue There are a few restrictions: 1. The lines should have been joined in the original source. 2. The joined lines must not go over the column boundary if placed on the same line. 3. They need to be very simple statements. Note: Because we don't allow the use of a semicolon to separate statements, it follows that there can only be at most two lines to join. """ from yapf.yapflib import style _CLASS_OR_FUNC = frozenset({'def', 'class'}) 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 code base. last_was_merged: (bool) The last line was merged. Returns: 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? 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 considered "simple" statements --- typically statements like 'pass', 'continue', and 'break'. Arguments: lines: (list of LogicalLine) The lines we are wanting to merge. limit: (int) The amount of space remaining on the line. 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') yapf-0.32.0/yapf/yapflib/logical_line.py000066400000000000000000000621671416201014000201140ustar00rootroot00000000000000# 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. """LogicalLine primitive for formatting. 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 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 from lib2to3.fixer_util import syms as python_symbols 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 distinguish lines that are more deeply nested than others. It is not the actual amount of spaces, which is style-dependent. """ 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 next_token and previous_token attributes. Arguments: 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) 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.""" 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. TODO(eliben): for now this is rudimentary for debugging - once we add formatting capabilities, this method will have other uses (not all tokens have spaces around them, for example). Arguments: indent_per_depth: how much spaces to indend per depth level. 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 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) ############################################################################ # Properties # ############################################################################ @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 @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 @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 @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 _IsUnaryOperator(tok): return subtypes.UNARY_OPERATOR in tok.subtypes 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 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 _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 lval in pytree_utils.OPENING_BRACKETS and rval == ':': 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 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 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 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 (lval in pytree_utils.OPENING_BRACKETS and rval in pytree_utils.OPENING_BRACKETS): # 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, 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, 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, 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, unless enabled # by SPACE_INSIDE_BRACKETS. return style.Get('SPACE_INSIDE_BRACKETS') if (lval in pytree_utils.OPENING_BRACKETS 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 yapf-0.32.0/yapf/yapflib/object_state.py000066400000000000000000000176721416201014000201420ustar00rootroot00000000000000# 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 from yapf.yapflib import format_token from yapf.yapflib import py3compat from yapf.yapflib import style from yapf.yapflib import subtypes 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. 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. 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)) class ParameterListState(object): """Maintains the state of function parameter list formatting decisions. 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. 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. 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) @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. 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): 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 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)) yapf-0.32.0/yapf/yapflib/py3compat.py000066400000000000000000000102561416201014000174020ustar00rootroot00000000000000# 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 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 else: import __builtin__ import cStringIO 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 from itertools import ifilter raw_input = raw_input import ConfigParser as configparser CONFIGPARSER_BOOLEAN_STATES = configparser.ConfigParser._boolean_states # pylint: disable=protected-access # noqa 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 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 yapf-0.32.0/yapf/yapflib/pytree_unwrapper.py000066400000000000000000000346341416201014000211040ustar00rootroot00000000000000# 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. """PyTreeUnwrapper - produces a list of logical lines from a pytree. [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 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 for the tree to have its comments spliced in as nodes. Prefixes are ignored. For most uses, the convenience function UnwrapPyTree should be sufficient. """ # 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.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 def UnwrapPyTree(tree): """Create and return a list of logical lines from the given pytree. Arguments: tree: the top-level pytree node to unwrap.. Returns: A list of LogicalLine objects. """ 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 ]) 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 Visit_node_name. invalid-name pragmas are added to each such method to silence a style warning. This is forced on us by the usage of lib2to3, and re-munging method names to make them different from actual node names sounded like a confusing and brittle affair that wasn't worth it for this small & controlled deviation from the style guide. To understand the connection between visitor methods in this class, some familiarity with the Python grammar is required. """ 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) # Current indentation depth. self._cur_depth = 0 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 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. Python compound statements serve as containers for other statements. Thus, when we encounter a new compound statement, we start a new logical line. Arguments: node: the node to visit. 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) _IF_STMT_ELEMS = frozenset({'if', 'else', 'elif'}) def Visit_if_stmt(self, node): # pylint: disable=invalid-name self._VisitCompoundStatement(node, self._IF_STMT_ELEMS) _WHILE_STMT_ELEMS = frozenset({'while', 'else'}) def Visit_while_stmt(self, node): # pylint: disable=invalid-name self._VisitCompoundStatement(node, self._WHILE_STMT_ELEMS) _FOR_STMT_ELEMS = frozenset({'for', 'else'}) 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'}) def Visit_try_stmt(self, node): # pylint: disable=invalid-name self._VisitCompoundStatement(node, self._TRY_STMT_ELEMS) _EXCEPT_STMT_ELEMS = frozenset({'except'}) def Visit_except_clause(self, node): # pylint: disable=invalid-name self._VisitCompoundStatement(node, self._EXCEPT_STMT_ELEMS) _FUNC_DEF_ELEMS = frozenset({'def'}) 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) _CLASS_DEF_ELEMS = frozenset({'class'}) 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': 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_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_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_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 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.AppendNode(leaf) _BRACKET_MATCH = {')': '(', '}': '{', ']': '['} 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 or close bracket. Arguments: line: (LogicalLine) A logical line. """ bracket_stack = [] 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: 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 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: 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 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) # 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. 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: 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 pytree_utils.OPENING_BRACKETS: bracket_level += 1 elif token.value in pytree_utils.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 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 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) yapf-0.32.0/yapf/yapflib/pytree_utils.py000066400000000000000000000252661416201014000202220ustar00rootroot00000000000000# 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. """pytree-related utilities. This module collects various utilities related to the parse trees produced by the lib2to3 library. NodeName(): produces a string name for pytree nodes. ParseCodeToTree(): convenience wrapper around lib2to3 interfaces to parse a given string with code to a pytree. InsertNodeBefore(): insert a node before another in a pytree. InsertNodeAfter(): insert a node after another in a pytree. {Get,Set}NodeAnnotation(): manage custom annotations on pytree nodes. """ 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 # 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, # these tokens may be filtered out from the tree before the tree gets to the # unwrapper. NONSEMANTIC_TOKENS = frozenset(['DEDENT', 'INDENT', 'NEWLINE', 'ENDMARKER']) OPENING_BRACKETS = frozenset({'(', '[', '{'}) CLOSING_BRACKETS = frozenset({')', ']', '}'}) 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. For a Leaf this is the token name, and for a Node this is the type. Arguments: node: a tree 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] 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). # 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'] def ParseCodeToTree(code): """Parse the given code to a lib2to3 pytree. Arguments: code: a string with the code to parse. Raises: SyntaxError if the code is invalid syntax. parse.ParseError if some other parsing failure. 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. 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. Returns: The root node of the parsed tree. If the tree is a single ENDMARKER node, 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 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 tree). target: the target node before which the new node node will be inserted. Raises: RuntimeError: if the tree is corrupted, or the insertion would corrupt it. """ 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. Arguments: new_nodes: a sequence of new nodes to insert (the nodes should not be in the tree). target: the target node after which the new node node will be inserted. Raises: RuntimeError: if the tree is corrupted, or the insertion would corrupt it. """ for node in reversed(new_nodes): _InsertNodeAt(node, target, after=True) 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). target: the target node. after: if True, new_node is inserted after target. Otherwise, it's inserted before target. Returns: nothing Raises: 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)) # 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 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 # managed through GetNodeAnnotation and SetNodeAnnotation. _NODE_ANNOTATION_PREFIX = '_yapf_annotation_' 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)) def GetNodeAnnotation(node, annotation, default=None): """Get annotation value from a node. Arguments: node: the node. annotation: annotation name - a string. default: the default value to return if there's no annotation. Returns: 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) 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) 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) 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) 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. Arguments: node: the 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) yapf-0.32.0/yapf/yapflib/pytree_visitor.py000066400000000000000000000106611416201014000205520ustar00rootroot00000000000000# 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. """Generic visitor pattern for pytrees. The lib2to3 parser produces a "pytree" - syntax tree consisting of Node and Leaf types. This module implements a visitor pattern for such trees. It also exports a basic "dumping" visitor that dumps a textual representation of a pytree into a stream. PyTreeVisitor: a generic visitor pattern for pytrees. PyTreeDumper: a configurable "dumper" for displaying pytrees. DumpPyTree(): a convenience function to dump a pytree. """ import sys from lib2to3 import pytree from yapf.yapflib import pytree_utils 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 grammar symbols (for Node nodes). The return value of Visit_XXX methods is ignored by the visitor. Visitors can modify node contents but must not change the tree structure (e.g. add/remove children and move nodes around). This is a very common visitor pattern in Python code; it's also used in the Python standard library ast module for providing AST visitors. Note: this makes names that aren't style conformant, so such visitor methods need to be marked with # pylint: disable=invalid-name We don't have a choice here, because lib2to3 nodes have under_separated names. For more complex behavior, the visit, DefaultNodeVisit and DefaultLeafVisit methods can be overridden. Don't forget to invoke DefaultNodeVisit for nodes 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. 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) 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 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 directly. Arguments: tree: the tree to dump. 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) 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. 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)) yapf-0.32.0/yapf/yapflib/reformatter.py000066400000000000000000000670531416201014000200240ustar00rootroot00000000000000# 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. """Decide what the format for the code should be. 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. """ from __future__ import unicode_literals import collections import heapq import re from lib2to3 import pytree from lib2to3.pgen2 import token 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 def Reformat(llines, verify=False, 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. 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.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(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 _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 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') 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) 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 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 convention. Instead, we calculate when / if a newline should occur and honor that. But otherwise the code emitted will be the same as the original code. Arguments: 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 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 state.AddTokenToState(newline=newline, dry_run=False) 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: 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 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 _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. Arguments: 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 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') 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 = [] 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 for this node. newline: If True, then on the edge from 'previous.state' to 'state' a newline is inserted. previous: (_StateNode) The previous state node in the graph. """ # TODO(morbo): Add a '__cmp__' method. 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) # 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']) # An item in the prioritized BFS search queue. The 'StateNode's 'state' has # the given '_OrderedPenalty'. _QueueItem = collections.namedtuple('QueueItem', ['ordered_penalty', 'state_node']) 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 the shortest path (the one with the lowest penalty) from 'initial_state' to the state where all tokens are placed. Arguments: initial_state: (format_decision_state.FormatDecisionState) The initial state to start the search from. 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 _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. Assume the current state is 'previous_node' and has been reached with a penalty of 'penalty'. Insert a line break if 'newline' is True. Arguments: penalty: (int) The penalty associated with the path up to this point. previous_node: (_StateNode) The last _StateNode inserted into the priority queue. newline: (bool) Add a newline if True. count: (int) The number of elements in the queue. p_queue: (heapq) The priority queue representing the solution space. 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 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. Arguments: initial_state: (format_decision_state.FormatDecisionState) The initial state to start the search from. current: (_StateNode) The node in the decision graph that is the end point of the path with the least penalty. """ path = collections.deque() while current.previous: path.appendleft(current) current = current.previous 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. 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 logical line. indent_depth: (int) The line's indentation depth. 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: 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 _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 line. indent_depth: (int) The line's indentation depth. 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: 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: 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') if first_token_lineno - prev_last_token_lineno > 1: return ONE_BLANK_LINE return NO_BLANK_LINES def _SingleOrMergedLines(lines): """Generate the lines we want to format. Arguments: 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 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)) 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 gives us the extent and thus where the line number of the end of the docstring or comment. After that, we just compare it to the current token's line number to see if there are blank lines between them. Arguments: text: (unicode) The text of the docstring or comment before the current token. 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: 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 yapf-0.32.0/yapf/yapflib/split_penalty.py000066400000000000000000000576231416201014000203630ustar00rootroot00000000000000# 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. """Computation of split penalties before/between tokens.""" 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 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. 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 ONE_ELEMENT_ARGUMENT = 500 SUBSCRIPT = 6000 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) 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] _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 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 _SetExpressionPenalty(node, penalty): """Set 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_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)) 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. Args: tree: subtree to annotate 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) 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 {'==', 'in'}): 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) yapf-0.32.0/yapf/yapflib/style.py000066400000000000000000000762221416201014000166300ustar00rootroot00000000000000# 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. """Python formatting style settings.""" import os import re import textwrap from yapf.yapflib import errors from yapf.yapflib import py3compat 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 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 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."""), 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 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("""\ 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: 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("""\ 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: call_func_that_takes_a_dict( { 'key1': 'value1', 'key2': 'value2', } ) would reformat to: call_func_that_takes_a_dict({ 'key1': 'value1', 'key2': 'value2', })"""), 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 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("""\ 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: 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=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("""\ 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."""), 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("""\ 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: config = { 'key1': 'value1', '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("""\ Do not include spaces around selected binary operators. For example: 1 + 2 * 3 - 4 / 5 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."""), 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("""\ 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. 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). 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 """), # 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("""\ 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."""), 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': 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: 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)) """), # 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."""), 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("""\ 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("""\ 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("""\ 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("""\ 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: 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: 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."""), 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, 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 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 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 _STYLE_NAME_TO_FACTORY = dict( pep8=CreatePEP8Style, google=CreateGoogleStyle, facebook=CreateFacebookStyle, yapf=CreateYapfStyle, ) _DEFAULT_STYLE_TO_FACTORY = [ (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 _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 _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 _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.""" 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 # 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 # returns it wrapper in actual Python type that's going to be meaningful to # yapf. # # 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_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. Arguments: 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 _GLOBAL_STYLE_FACTORY config is created. Returns: A style dict. Raises: 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: 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. Returns: A style dict. 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 # The default style - used if yapf is not invoked without specifically # 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( 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' # Alternative place for directory-local style definition. Style should be # 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. _style = None SetGlobalStyle(_GLOBAL_STYLE_FACTORY()) yapf-0.32.0/yapf/yapflib/subtype_assigner.py000066400000000000000000000451451416201014000210560ustar00rootroot00000000000000# 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. """Subtype assigner for format tokens. 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 'subtypes' module for a list of subtypes. """ from lib2to3 import pytree 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 from yapf.yapflib import subtypes 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) # Map tokens in argument lists to their respective subtype. _ARGLIST_TOKEN_TO_SUBTYPE = { '=': subtypes.DEFAULT_OR_NAMED_ASSIGN, ':': subtypes.TYPED_NAME, '*': subtypes.VARARGS_STAR, '**': subtypes.KWARGS_STAR_STAR, } 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) 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 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) yapf-0.32.0/yapf/yapflib/subtypes.py000066400000000000000000000021701416201014000173350ustar00rootroot00000000000000# 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 yapf-0.32.0/yapf/yapflib/verifier.py000066400000000000000000000057421416201014000173020ustar00rootroot00000000000000# 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' yapf-0.32.0/yapf/yapflib/yapf_api.py000066400000000000000000000271461416201014000172610ustar00rootroot00000000000000# 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. """Entry points for YAPF. The main APIs that YAPF exposes to drive the reformatting. FormatFile(): reformat a file. FormatCode(): reformat a string of code. These APIs have some common arguments: 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. """ import difflib 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 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 pytree_unwrapper from yapf.yapflib import pytree_utils 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, 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. 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. Returns: Tuple of (reformatted_code, encoding, changed). reformatted_code is None if the file is successfully written to (having used in_place). reformatted_code is a diff if print_diff is True. Raises: 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. 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) 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. Arguments: unformatted_source: (unicode) The code to format. filename: (unicode) The name of the file being reformatted. 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 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)) 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 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 return reformatted_source, True def _CheckPythonVersion(): # pragma: no cover errmsg = 'yapf is only supported for Python 2.7 or 3.4+' 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: raise RuntimeError(errmsg) 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 can be used by third-party applications. Arguments: filename: (unicode) The name of the file. logger: (function) A function or lambda that takes a string and emits it. Returns: The contents of filename. 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 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 _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. after: (unicode) The reformatted source code. filename: (unicode) The code's filename. 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' yapf-0.32.0/yapftests/000077500000000000000000000000001416201014000145425ustar00rootroot00000000000000yapf-0.32.0/yapftests/__init__.py000066400000000000000000000011241416201014000166510ustar00rootroot00000000000000# 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. yapf-0.32.0/yapftests/blank_line_calculator_test.py000066400000000000000000000216711416201014000224710ustar00rootroot00000000000000# 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. """Tests for yapf.blank_line_calculator.""" import textwrap import unittest from yapf.yapflib import reformatter from yapf.yapflib import style from yapf.yapflib import yapf_api from yapftests import yapf_test_helper class BasicBlankLineCalculatorTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): style.SetGlobalStyle(style.CreateYapfStyle()) def testDecorators(self): unformatted_code = textwrap.dedent("""\ @bork() 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)) def testComplexDecorators(self): unformatted_code = textwrap.dedent("""\ import sys @bork() def foo(): pass @fork() class moo(object): @bar() @baz() def method(self): pass """) expected_formatted_code = textwrap.dedent("""\ import sys @bork() def foo(): pass @fork() class moo(object): @bar() @baz() def method(self): pass """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCodeAfterFunctionsAndClasses(self): unformatted_code = textwrap.dedent("""\ def foo(): pass top_level_code = True class moo(object): def method_1(self): pass ivar_a = 42 ivar_b = 13 def method_2(self): pass try: raise Error except Error as error: pass """) expected_formatted_code = textwrap.dedent("""\ def foo(): pass top_level_code = True class moo(object): def method_1(self): pass ivar_a = 42 ivar_b = 13 def method_2(self): pass try: raise Error except Error as error: pass """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentSpacing(self): unformatted_code = textwrap.dedent("""\ # This is the first comment # And it's multiline # This is the second comment def foo(): pass # multiline before a # class definition # This is the second comment class qux(object): pass # An attached comment. class bar(object): '''class docstring''' # Comment attached to # function def foo(self): '''Another docstring.''' # Another multiline # comment pass """) expected_formatted_code = textwrap.dedent("""\ # This is the first comment # And it's multiline # This is the second comment def foo(): pass # multiline before a # class definition # This is the second comment class qux(object): pass # An attached comment. class bar(object): '''class docstring''' # Comment attached to # function def foo(self): '''Another docstring.''' # Another multiline # comment pass """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testCommentBeforeMethod(self): code = textwrap.dedent("""\ class foo(object): # pylint: disable=invalid-name def f(self): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsBeforeClassDefs(self): code = textwrap.dedent('''\ """Test.""" # Comment class Foo(object): pass ''') llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsBeforeDecorator(self): code = textwrap.dedent("""\ # The @foo operator adds bork to a(). @foo() def a(): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ # Hello world @foo() def a(): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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 """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testInnerClasses(self): unformatted_code = textwrap.dedent("""\ class DeployAPIClient(object): class Error(Exception): pass class TaskValidationError(Error): pass class DeployAPIHTTPError(Error): pass """) expected_formatted_code = textwrap.dedent("""\ class DeployAPIClient(object): class Error(Exception): pass class TaskValidationError(Error): pass class DeployAPIHTTPError(Error): pass """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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) 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) self.assertTrue(changed) 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() yapf-0.32.0/yapftests/comment_splicer_test.py000066400000000000000000000253751416201014000213520ustar00rootroot00000000000000# 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. """Tests for yapf.comment_splicer.""" import textwrap import unittest from yapf.yapflib import comment_splicer from yapf.yapflib import py3compat from yapf.yapflib import pytree_utils class CommentSplicerTest(unittest.TestCase): def _AssertNodeType(self, expected_type, node): self.assertEqual(expected_type, pytree_utils.NodeName(node)) def _AssertNodeIsComment(self, node, text_in_comment=None): if pytree_utils.NodeName(node) == 'simple_stmt': self._AssertNodeType('COMMENT', node.children[0]) node_value = node.children[0].value else: self._AssertNodeType('COMMENT', node) node_value = node.value if text_in_comment is not 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())): if i == n - 1: return child raise RuntimeError('No Nth child for n={0}'.format(n)) def testSimpleInline(self): code = 'foo = 1 # and a comment\n' tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) expr = tree.children[0].children[0] # Check that the expected node is still expr_stmt, but now it has 4 children # (before comment splicing it had 3), the last child being the comment. self._AssertNodeType('expr_stmt', expr) self.assertEqual(4, len(expr.children)) comment_node = expr.children[3] self._AssertNodeIsComment(comment_node, '# and a comment') def testSimpleSeparateLine(self): code = textwrap.dedent(r''' foo = 1 # first comment bar = 2 ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) # The comment should've been added to the root's children (now 4, including # the ENDMARKER in the end. self.assertEqual(4, len(tree.children)) comment_node = tree.children[1] self._AssertNodeIsComment(comment_node) def testTwoLineComment(self): code = textwrap.dedent(r''' foo = 1 # first comment # second comment bar = 2 ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) # This is similar to the single-line standalone comment. self.assertEqual(4, len(tree.children)) self._AssertNodeIsComment(tree.children[1]) def testCommentIsFirstChildInCompound(self): code = textwrap.dedent(r''' if x: # a comment foo = 1 ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) # Look into the suite node under the 'if'. We don't care about the NEWLINE # leaf but the new COMMENT must be a child of the suite and before the # actual code leaf. if_suite = tree.children[0].children[3] self._AssertNodeType('NEWLINE', if_suite.children[0]) self._AssertNodeIsComment(if_suite.children[1]) def testCommentIsLastChildInCompound(self): code = textwrap.dedent(r''' if x: foo = 1 # a comment ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) # Look into the suite node under the 'if'. We don't care about the DEDENT # leaf but the new COMMENT must be a child of the suite and after the # actual code leaf. if_suite = tree.children[0].children[3] self._AssertNodeType('DEDENT', if_suite.children[-1]) self._AssertNodeIsComment(if_suite.children[-2]) def testInlineAfterSeparateLine(self): code = textwrap.dedent(r''' bar = 1 # line comment foo = 1 # inline comment ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) # The separate line comment should become a child of the root, while # the inline comment remains within its simple_node. sep_comment_node = tree.children[1] self._AssertNodeIsComment(sep_comment_node, '# line comment') 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''' bar = 1 foo = 1 # inline comment # line comment ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) # The separate line comment should become a child of the root, while # the inline comment remains within its simple_node. sep_comment_node = tree.children[-2] self._AssertNodeIsComment(sep_comment_node, '# line comment') 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''' if bar: z = 1 # a comment j = 2 ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) # The comment should go under the tree root, not under the 'if'. self._AssertNodeIsComment(tree.children[1]) if_suite = tree.children[0].children[3] self._AssertNodeType('DEDENT', if_suite.children[-1]) def testCommentBeforeDedentTwoLevel(self): code = textwrap.dedent(r''' if foo: if bar: z = 1 # a comment y = 1 ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) if_suite = tree.children[0].children[3] # The comment is in the first if_suite, not the nested if under it. It's # right before the DEDENT self._AssertNodeIsComment(if_suite.children[-2]) self._AssertNodeType('DEDENT', if_suite.children[-1]) def testCommentBeforeDedentTwoLevelImproperlyIndented(self): code = textwrap.dedent(r''' if foo: if bar: z = 1 # comment 2 y = 1 ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) # The comment here is indented by 3 spaces, which is unlike any of the # surrounding statement indentation levels. The splicer attaches it to the # "closest" parent with smaller indentation. if_suite = tree.children[0].children[3] # The comment is in the first if_suite, not the nested if under it. It's # right before the DEDENT 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: """docstring abc...""" # top-level comment def foo(): pass # another comment ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) 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] toplevel_comment = funcdef.children[0] self._AssertNodeIsComment(toplevel_comment, '# top-level') def testMultipleBlockComments(self): code = textwrap.dedent(r''' # Block comment number 1 # Block comment number 2 def f(): pass ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) funcdef = tree.children[0] block_comment_1 = funcdef.children[0] self._AssertNodeIsComment(block_comment_1, '# Block comment number 1') block_comment_2 = funcdef.children[1] self._AssertNodeIsComment(block_comment_2, '# Block comment number 2') def testCommentsOnDedents(self): code = textwrap.dedent(r''' class Foo(object): # A comment for qux. def qux(self): pass # Interim comment. def mux(self): pass ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) classdef = tree.children[0] class_suite = classdef.children[6] qux_comment = class_suite.children[1] self._AssertNodeIsComment(qux_comment, '# A comment for qux.') interim_comment = class_suite.children[4] self._AssertNodeIsComment(interim_comment, '# Interim comment.') def testExprComments(self): code = textwrap.dedent(r''' foo( # Request fractions of an hour. 948.0/3600, 20) ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) trailer = self._FindNthChildNamed(tree, 'trailer', 1) comment = trailer.children[1] 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 ) ''') tree = pytree_utils.ParseCodeToTree(code) comment_splicer.SpliceComments(tree) trailer = self._FindNthChildNamed(tree, 'trailer', 1) self._AssertNodeIsComment(trailer.children[1], '# com 1') arglist = self._FindNthChildNamed(tree, 'arglist', 1) self._AssertNodeIsComment(arglist.children[2], '# com 2') arith_expr = self._FindNthChildNamed(tree, 'arith_expr', 1) self._AssertNodeIsComment(arith_expr.children[-1], '# com 3') if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/file_resources_test.py000066400000000000000000000460021416201014000211660ustar00rootroot00000000000000# -*- coding: utf-8 -*- # 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. """Tests for yapf.file_resources.""" import contextlib import os import shutil import tempfile import unittest from yapf.yapflib import errors from yapf.yapflib import file_resources from yapf.yapflib import py3compat from yapftests import utils @contextlib.contextmanager def _restore_working_dir(): curdir = os.getcwd() try: yield 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): def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() def tearDown(self): # pylint: disable=g-missing-super-call shutil.rmtree(self.test_tmpdir) 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)) 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(['"{}"'.format(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 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 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)), sorted(ignore_patterns)) class GetDefaultStyleForDirTest(unittest.TestCase): def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() 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') 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') open(style_file, 'w').close() test_filename = os.path.join(self.test_tmpdir, 'file.py') 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)) 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_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() 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) 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: open(name, 'a').close() class GetCommandLineFilesTest(unittest.TestCase): def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() self.old_dir = os.getcwd() def tearDown(self): # pylint: disable=g-missing-super-call 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)) os.makedirs(fullpath) return fullpath def test_find_files_not_dirs(self): tdir1 = self._make_test_dir('test1') tdir2 = self._make_test_dir('test2') file1 = os.path.join(tdir1, 'testfile1.py') file2 = os.path.join(tdir2, 'testfile2.py') _touch_files([file1, file2]) self.assertEqual( file_resources.GetCommandLineFiles([file1, file2], recursive=False, exclude=None), [file1, file2]) self.assertEqual( file_resources.GetCommandLineFiles([file1, file2], recursive=True, exclude=None), [file1, file2]) def test_nonrecursive_find_in_dir(self): tdir1 = self._make_test_dir('test1') tdir2 = self._make_test_dir('test1/foo') file1 = os.path.join(tdir1, 'testfile1.py') file2 = os.path.join(tdir2, 'testfile2.py') _touch_files([file1, file2]) self.assertRaises( errors.YapfError, file_resources.GetCommandLineFiles, command_line_file_list=[tdir1], recursive=False, exclude=None) 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'), ] _touch_files(files) self.assertEqual( sorted( 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') 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) 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'), ])) 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): """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 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/') 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'.replace("/", os.path.sep)]) found = sorted( file_resources.GetCommandLineFiles(['.'], recursive=True, exclude=[ 'test1', 'test3', ])) self.assertEqual( found, ['./test2/testinner/testfile2.py'.replace("/", os.path.sep)]) def test_find_with_excluded_current_dir(self): with self.assertRaises(errors.YapfError): file_resources.GetCommandLineFiles([], False, exclude=['./z']) class IsPythonFileTest(unittest.TestCase): def setUp(self): # pylint: disable=g-missing-super-call self.test_tmpdir = tempfile.mkdtemp() def tearDown(self): # pylint: disable=g-missing-super-call shutil.rmtree(self.test_tmpdir) def test_with_py_extension(self): file1 = os.path.join(self.test_tmpdir, 'testfile1.py') self.assertTrue(file_resources.IsPythonFile(file1)) def test_empty_without_py_extension(self): file1 = os.path.join(self.test_tmpdir, 'testfile1') self.assertFalse(file_resources.IsPythonFile(file1)) file2 = os.path.join(self.test_tmpdir, 'testfile1.rb') self.assertFalse(file_resources.IsPythonFile(file2)) 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') 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') self.assertTrue(file_resources.IsPythonFile(file1)) 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: f.write(u'#! /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') 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' + os.path.sep])) class BufferedByteStream(object): def __init__(self): self.stream = py3compat.BytesIO() def getvalue(self): # pylint: disable=invalid-name return self.stream.getvalue().decode('utf-8') @property def buffer(self): return self.stream class WriteReformattedCodeTest(unittest.TestCase): @classmethod def setUpClass(cls): # pylint: disable=g-missing-super-call cls.test_tmpdir = tempfile.mkdtemp() @classmethod def tearDownClass(cls): # pylint: disable=g-missing-super-call shutil.rmtree(cls.test_tmpdir) def test_write_to_file(self): s = u'foobar\n' with utils.NamedTempFile(dirname=self.test_tmpdir) as (f, fname): file_resources.WriteReformattedCode( fname, s, in_place=True, encoding='utf-8') f.flush() with open(fname) as f2: self.assertEqual(f2.read(), s) def test_write_to_stdout(self): s = u'foobar' stream = BufferedByteStream() if py3compat.PY3 else py3compat.StringIO() with utils.stdout_redirector(stream): file_resources.WriteReformattedCode( None, s, in_place=False, encoding='utf-8') 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 stream = BufferedByteStream() if py3compat.PY3 else py3compat.StringIO() with utils.stdout_redirector(stream): file_resources.WriteReformattedCode( None, s, in_place=False, encoding='utf-8') 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() yapf-0.32.0/yapftests/format_decision_state_test.py000066400000000000000000000104561416201014000225260ustar00rootroot00000000000000# 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. """Tests for yapf.format_decision_state.""" import textwrap 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 yapftests import yapf_test_helper class FormatDecisionStateTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): style.SetGlobalStyle(style.CreateYapfStyle()) def testSimpleFunctionDefWithNoSplitting(self): code = textwrap.dedent(r""" def f(a, b): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) lline.CalculateFormattingInformation() # Add: 'f' state = format_decision_state.FormatDecisionState(lline, 0) state.MoveStateToNextToken() self.assertEqual('f', state.next_token.value) self.assertFalse(state.CanSplit(False)) # Add: '(' state.AddTokenToState(False, True) self.assertEqual('(', state.next_token.value) 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(False)) self.assertFalse(state.MustSplit()) # Add: ',' state.AddTokenToState(False, True) self.assertEqual(',', state.next_token.value) 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(False)) self.assertFalse(state.MustSplit()) # Add: ')' state.AddTokenToState(False, True) self.assertEqual(')', state.next_token.value) self.assertTrue(state.CanSplit(False)) self.assertFalse(state.MustSplit()) # Add: ':' state.AddTokenToState(False, True) self.assertEqual(':', state.next_token.value) self.assertFalse(state.CanSplit(False)) self.assertFalse(state.MustSplit()) clone = state.Clone() self.assertEqual(repr(state), repr(clone)) def testSimpleFunctionDefWithSplitting(self): code = textwrap.dedent(r""" def f(a, b): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) lline = logical_line.LogicalLine(0, _FilterLine(llines[0])) lline.CalculateFormattingInformation() # Add: 'f' state = format_decision_state.FormatDecisionState(lline, 0) state.MoveStateToNextToken() self.assertEqual('f', state.next_token.value) self.assertFalse(state.CanSplit(False)) # Add: '(' state.AddTokenToState(True, True) self.assertEqual('(', state.next_token.value) self.assertFalse(state.CanSplit(False)) # Add: 'a' state.AddTokenToState(True, True) self.assertEqual('a', state.next_token.value) self.assertTrue(state.CanSplit(False)) # Add: ',' state.AddTokenToState(True, True) self.assertEqual(',', state.next_token.value) self.assertFalse(state.CanSplit(False)) # Add: 'b' state.AddTokenToState(True, True) self.assertEqual('b', state.next_token.value) self.assertTrue(state.CanSplit(False)) # Add: ')' state.AddTokenToState(True, True) self.assertEqual(')', state.next_token.value) self.assertTrue(state.CanSplit(False)) # Add: ':' state.AddTokenToState(True, True) self.assertEqual(':', state.next_token.value) self.assertFalse(state.CanSplit(False)) clone = state.Clone() self.assertEqual(repr(state), repr(clone)) def _FilterLine(lline): """Filter out nonsemantic tokens from the LogicalLines.""" return [ ft for ft in lline.tokens if ft.name not in pytree_utils.NONSEMANTIC_TOKENS ] if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/format_token_test.py000066400000000000000000000056101416201014000206450ustar00rootroot00000000000000# 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. """Tests for yapf.format_token.""" import unittest from lib2to3 import pytree from lib2to3.pgen2 import token from yapf.yapflib import format_token class TabbedContinuationAlignPaddingTest(unittest.TestCase): def testSpace(self): align_style = 'SPACE' pad = format_token._TabbedContinuationAlignPadding(0, align_style, 2) self.assertEqual(pad, '') pad = format_token._TabbedContinuationAlignPadding(2, align_style, 2) self.assertEqual(pad, ' ' * 2) 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) self.assertEqual(pad, '') pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4) self.assertEqual(pad, '\t') 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) self.assertEqual(pad, '') pad = format_token._TabbedContinuationAlignPadding(2, align_style, 4) self.assertEqual(pad, '\t') pad = format_token._TabbedContinuationAlignPadding(4, align_style, 4) self.assertEqual(pad, '\t') pad = format_token._TabbedContinuationAlignPadding(5, align_style, 4) self.assertEqual(pad, '\t' * 2) 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, 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, splitpenalty=0)', 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) if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/line_joiner_test.py000066400000000000000000000050741416201014000204560ustar00rootroot00000000000000# 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. """Tests for yapf.line_joiner.""" import textwrap import unittest from yapf.yapflib import line_joiner from yapf.yapflib import style from yapftests import yapf_test_helper class LineJoinerTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): style.SetGlobalStyle(style.CreatePEP8Style()) def _CheckLineJoining(self, code, join_lines): """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. """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(line_joiner.CanMergeMultipleLines(llines), join_lines) def testSimpleSingleLineStatement(self): code = textwrap.dedent(u"""\ if isinstance(a, int): continue """) self._CheckLineJoining(code, join_lines=True) def testSimpleMultipleLineStatement(self): code = textwrap.dedent(u"""\ if isinstance(b, int): continue """) self._CheckLineJoining(code, join_lines=False) def testSimpleMultipleLineComplexStatement(self): code = textwrap.dedent(u"""\ if isinstance(c, int): while True: continue """) self._CheckLineJoining(code, join_lines=False) def testSimpleMultipleLineStatementWithComment(self): 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"""\ if isinstance(e, int): continue """) self._CheckLineJoining(code, join_lines=True) def testOverColumnLimit(self): code = textwrap.dedent(u"""\ if instance(bbbbbbbbbbbbbbbbbbbbbbbbb, int): cccccccccccccccccccccccccc = ddddddddddddddddddddd """) # noqa self._CheckLineJoining(code, join_lines=False) if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/logical_line_test.py000066400000000000000000000062251416201014000206010ustar00rootroot00000000000000# 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. """Tests for yapf.logical_line.""" import textwrap import unittest from lib2to3 import pytree from lib2to3.pgen2 import token from yapf.yapflib import format_token from yapf.yapflib import logical_line from yapf.yapflib import split_penalty from yapftests import yapf_test_helper class LogicalLineBasicTest(unittest.TestCase): def testConstruction(self): toks = _MakeFormatTokenList([(token.DOT, '.'), (token.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, '|')]) 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, '|')]) 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, ')')) 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): def testFuncDef(self): code = textwrap.dedent(r""" def f(a, b): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) 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 = llines[0].tokens[2] self.assertFalse(lparen.can_break_before) self.assertFalse(lparen.must_break_before) 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() yapf-0.32.0/yapftests/main_test.py000066400000000000000000000076411416201014000171070ustar00rootroot00000000000000# -*- coding: utf-8 -*- # 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. """Tests for yapf.__init__.main.""" from contextlib import contextmanager import sys import unittest import yapf from yapf.yapflib import py3compat from yapftests import yapf_test_helper 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 = py3compat.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 = IO(), IO() old_out, old_err = sys.stdout, sys.stderr try: sys.stdout, sys.stderr = new_out, new_err yield sys.stdout, sys.stderr finally: sys.stdout, sys.stderr = old_out, old_err @contextmanager def patched_input(code): """Monkey patch code as though it were coming from stdin.""" def lines(): for line in code.splitlines(): yield line raise EOFError() def patch_raw_input(lines=lines()): return next(lines) try: orig_raw_import = yapf.py3compat.raw_input yapf.py3compat.raw_input = patch_raw_input yield finally: yapf.py3compat.raw_input = orig_raw_import 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'] with captured_output() as (out, err): with self.assertRaises(SystemExit): yapf.run_main() self.assertEqual(out.getvalue(), '') self.assertEqual(err.getvalue(), expected_message) class MainTest(yapf_test_helper.YAPFTest): def testNoPythonFilesMatched(self): with self.assertRaisesRegex(yapf.errors.YapfError, 'did not match any python files'): yapf.main(['yapf', 'foo.c']) def testEchoInput(self): code = 'a = 1\nb = 2\n' with patched_input(code): 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\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, _): ret = yapf.main(['-', '--style=yapf']) self.assertEqual(ret, 0) self.assertEqual(out.getvalue(), yapf_code) def testEchoBadInput(self): bad_syntax = ' a = 1\n' with patched_input(bad_syntax): with captured_output() as (_, _): with self.assertRaisesRegex(yapf.errors.YapfError, 'unexpected indent'): yapf.main([]) def testHelp(self): 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.', help_message) yapf-0.32.0/yapftests/pytree_unwrapper_test.py000066400000000000000000000221101416201014000215620ustar00rootroot00000000000000# 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. """Tests for yapf.pytree_unwrapper.""" import textwrap import unittest from yapf.yapflib import pytree_utils from yapftests import yapf_test_helper class PytreeUnwrapperTest(yapf_test_helper.YAPFTest): def _CheckLogicalLines(self, llines, list_of_expected): """Check that the given LogicalLines match expectations. Args: llines: list of LogicalLine list_of_expected: list of (depth, values) pairs. Non-semantic tokens are filtered out from the expected values. """ actual = [] for lline in llines: filtered_values = [ ft.value for ft in lline.tokens if ft.name not in pytree_utils.NONSEMANTIC_TOKENS ] actual.append((lline.depth, filtered_values)) self.assertEqual(list_of_expected, actual) def testSimpleFileScope(self): 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']), ]) def testSimpleMultilineStatement(self): code = textwrap.dedent(r""" 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 """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['x', '=', '1', '# a comment']), (0, ['y', '=', '2']), ]) def testSimpleIf(self): 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']), ]) def testSimpleIfWithComments(self): 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']), ]) def testIfWithCommentsInside(self): code = textwrap.dedent(r""" if foo: # c1 x = 1 # c2 # c3 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']), ]) def testIfElifElse(self): code = textwrap.dedent(r""" 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', ':']), (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""" if x: x = 1 # c1 while t: # c2 j = 1 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']), ]) def testSimpleWhile(self): 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']), ]) def testSimpleTry(self): code = textwrap.dedent(r""" try: pass except: pass except: pass else: pass finally: 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']), ]) def testSimpleFuncdef(self): 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']), ]) def testTwoFuncDefs(self): code = textwrap.dedent(r""" 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']), (1, ['# c2']), (1, ['return', 'x']), (0, ['def', 'bar', '(', ')', ':', '# c3']), (1, ['# c4']), (1, ['return', 'x']), ]) def testSimpleClassDef(self): 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']), ]) def testSingleLineStmtInFunc(self): code = textwrap.dedent(r""" def f(): return 37 """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['def', 'f', '(', ')', ':']), (1, ['return', '37']), ]) def testMultipleComments(self): code = textwrap.dedent(r""" # Comment #1 # Comment #2 def f(): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckLogicalLines(llines, [ (0, ['# Comment #1']), (0, ['# Comment #2']), (0, ['def', 'f', '(', ')', ':']), (1, ['pass']), ]) def testSplitListWithComment(self): code = textwrap.dedent(r""" a = [ 'a', 'b', 'c', # hello world ] """) 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, llines, list_of_expected): """Check that the tokens have the expected matching bracket. Arguments: 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 lline in llines: 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) for index, bracket_list in enumerate(list_of_expected): lline = actual[index] if not bracket_list: for value in lline: self.assertIsNone(value[1]) else: for open_bracket, close_bracket in bracket_list: 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 """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckMatchingBrackets(llines, [ [(2, 20), (7, 11), (15, 19)], [], ]) def testDecorator(self): code = textwrap.dedent("""\ @bar() def foo(a, b, c): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckMatchingBrackets(llines, [ [(2, 3)], [(2, 8)], [], ]) def testClassDef(self): code = textwrap.dedent("""\ class A(B, C, D): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckMatchingBrackets(llines, [ [(2, 8)], [], ]) if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/pytree_utils_test.py000066400000000000000000000177141416201014000207150ustar00rootroot00000000000000# 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. """Tests for yapf.pytree_utils.""" import unittest from lib2to3 import pygram from lib2to3 import pytree from lib2to3.pgen2 import token from yapf.yapflib import pytree_utils # More direct access to the symbol->number mapping living within the grammar # module. _GRAMMAR_SYMBOL2NUMBER = pygram.python_grammar.symbol2number _FOO = 'foo' _FOO1 = 'foo1' _FOO2 = 'foo2' _FOO3 = 'foo3' _FOO4 = 'foo4' _FOO5 = 'foo5' class NodeNameTest(unittest.TestCase): def testNodeNameForLeaf(self): leaf = pytree.Leaf(token.LPAR, '(') self.assertEqual('LPAR', pytree_utils.NodeName(leaf)) def testNodeNameForNode(self): leaf = pytree.Leaf(token.LPAR, '(') node = pytree.Node(pygram.python_grammar.symbol2number['suite'], [leaf]) self.assertEqual('suite', pytree_utils.NodeName(node)) class ParseCodeToTreeTest(unittest.TestCase): def testParseCodeToTree(self): # Since ParseCodeToTree is a thin wrapper around underlying lib2to3 # functionality, only a sanity test here... tree = pytree_utils.ParseCodeToTree('foo = 2\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])) def testPrintFunctionToTree(self): tree = pytree_utils.ParseCodeToTree( 'print("hello world", file=sys.stderr)\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])) 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])) 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])) class InsertNodesBeforeAfterTest(unittest.TestCase): def _BuildSimpleTree(self): # Builds a simple tree we can play with in the tests. # The tree looks like this: # # suite: # LPAR # LPAR # 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]) def _MakeNewNodeRPAR(self): return pytree.Leaf(token.RPAR, ')') def setUp(self): self._simple_tree = self._BuildSimpleTree() 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]) 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])) def testInsertNodesBeforeFirstChild(self): # Insert before the first child of its parent simple_stmt = self._simple_tree.children[2] 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)) self.assertEqual('RPAR', pytree_utils.NodeName(simple_stmt.children[0])) self.assertEqual('NAME', pytree_utils.NodeName(simple_stmt.children[1])) def testInsertNodesAfter(self): # Insert after and make sure it went to the right place 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])) def testInsertNodesAfterLastChild(self): # Insert after the last child of its parent simple_stmt = self._simple_tree.children[2] 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)) self.assertEqual('NAME', pytree_utils.NodeName(simple_stmt.children[0])) self.assertEqual('RPAR', pytree_utils.NodeName(simple_stmt.children[1])) 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]) 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')]) def testGetWhenNone(self): self.assertIsNone(pytree_utils.GetNodeAnnotation(self._leaf, _FOO)) def testSetWhenNone(self): pytree_utils.SetNodeAnnotation(self._leaf, _FOO, 20) self.assertEqual(pytree_utils.GetNodeAnnotation(self._leaf, _FOO), 20) def testSetAgain(self): pytree_utils.SetNodeAnnotation(self._leaf, _FOO, 20) self.assertEqual(pytree_utils.GetNodeAnnotation(self._leaf, _FOO), 20) pytree_utils.SetNodeAnnotation(self._leaf, _FOO, 30) self.assertEqual(pytree_utils.GetNodeAnnotation(self._leaf, _FOO), 30) def testMultiple(self): pytree_utils.SetNodeAnnotation(self._leaf, _FOO, 20) pytree_utils.SetNodeAnnotation(self._leaf, _FOO1, 1) pytree_utils.SetNodeAnnotation(self._leaf, _FOO2, 2) pytree_utils.SetNodeAnnotation(self._leaf, _FOO3, 3) pytree_utils.SetNodeAnnotation(self._leaf, _FOO4, 4) pytree_utils.SetNodeAnnotation(self._leaf, _FOO5, 5) self.assertEqual(pytree_utils.GetNodeAnnotation(self._leaf, _FOO), 20) self.assertEqual(pytree_utils.GetNodeAnnotation(self._leaf, _FOO1), 1) self.assertEqual(pytree_utils.GetNodeAnnotation(self._leaf, _FOO2), 2) self.assertEqual(pytree_utils.GetNodeAnnotation(self._leaf, _FOO3), 3) self.assertEqual(pytree_utils.GetNodeAnnotation(self._leaf, _FOO4), 4) self.assertEqual(pytree_utils.GetNodeAnnotation(self._leaf, _FOO5), 5) def testSubtype(self): pytree_utils.AppendNodeAnnotation(self._leaf, pytree_utils.Annotation.SUBTYPE, _FOO) self.assertSetEqual( 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()) def testSetOnNode(self): pytree_utils.SetNodeAnnotation(self._node, _FOO, 20) self.assertEqual(pytree_utils.GetNodeAnnotation(self._node, _FOO), 20) if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/pytree_visitor_test.py000066400000000000000000000077441416201014000212560ustar00rootroot00000000000000# 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. """Tests for yapf.pytree_visitor.""" import unittest from yapf.yapflib import py3compat from yapf.yapflib import pytree_utils from yapf.yapflib import pytree_visitor class _NodeNameCollector(pytree_visitor.PyTreeVisitor): """A tree visitor that collects the names of all tree nodes into a list. Attributes: all_node_names: collected list of the names, available when the traversal is over. name_node_values: collects a list of NAME leaves (in addition to those going into all_node_names). """ def __init__(self): self.all_node_names = [] self.name_node_values = [] def DefaultNodeVisit(self, node): self.all_node_names.append(pytree_utils.NodeName(node)) super(_NodeNameCollector, self).DefaultNodeVisit(node) def DefaultLeafVisit(self, leaf): self.all_node_names.append(pytree_utils.NodeName(leaf)) def Visit_NAME(self, leaf): self.name_node_values.append(leaf.value) self.DefaultLeafVisit(leaf) _VISITOR_TEST_SIMPLE_CODE = r""" foo = bar baz = x """ _VISITOR_TEST_NESTED_CODE = r""" if x: if y: return z """ class PytreeVisitorTest(unittest.TestCase): def testCollectAllNodeNamesSimpleCode(self): tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) collector = _NodeNameCollector() collector.Visit(tree) expected_names = [ 'file_input', 'simple_stmt', 'expr_stmt', 'NAME', 'EQUAL', 'NAME', 'NEWLINE', 'simple_stmt', 'expr_stmt', 'NAME', 'EQUAL', 'NAME', 'NEWLINE', 'ENDMARKER', ] # yapf: disable self.assertEqual(expected_names, collector.all_node_names) expected_name_node_values = ['foo', 'bar', 'baz', 'x'] self.assertEqual(expected_name_node_values, collector.name_node_values) def testCollectAllNodeNamesNestedCode(self): tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_NESTED_CODE) collector = _NodeNameCollector() collector.Visit(tree) expected_names = [ 'file_input', 'if_stmt', 'NAME', 'NAME', 'COLON', 'suite', 'NEWLINE', 'INDENT', 'if_stmt', 'NAME', 'NAME', 'COLON', 'suite', 'NEWLINE', 'INDENT', 'simple_stmt', 'return_stmt', 'NAME', 'NAME', 'NEWLINE', 'DEDENT', 'DEDENT', 'ENDMARKER', ] # yapf: disable self.assertEqual(expected_names, collector.all_node_names) expected_name_node_values = ['if', 'x', 'if', 'y', 'return', 'z'] self.assertEqual(expected_name_node_values, collector.name_node_values) 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() pytree_visitor.PyTreeDumper(target_stream=stream).Visit(tree) dump_output = stream.getvalue() self.assertIn('file_input [3 children]', dump_output) self.assertIn("NAME(Leaf(NAME, 'foo'))", dump_output) self.assertIn("EQUAL(Leaf(EQUAL, '='))", dump_output) def testDumpPyTree(self): # Similar sanity checking for the convenience wrapper DumpPyTree tree = pytree_utils.ParseCodeToTree(_VISITOR_TEST_SIMPLE_CODE) stream = py3compat.StringIO() pytree_visitor.DumpPyTree(tree, target_stream=stream) dump_output = stream.getvalue() self.assertIn('file_input [3 children]', dump_output) self.assertIn("NAME(Leaf(NAME, 'foo'))", dump_output) self.assertIn("EQUAL(Leaf(EQUAL, '='))", dump_output) if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/reformatter_basic_test.py000066400000000000000000003261261416201014000216600ustar00rootroot00000000000000# 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. """Basic tests for yapf.reformatter.""" 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 class BasicReformatterTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): style.SetGlobalStyle(style.CreateYapfStyle()) 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} """) # noqa expected_formatted_code = textwrap.dedent("""\ 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', } """) expected_formatted_code = textwrap.dedent("""\ 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): 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 expected_formatted_code = textwrap.dedent("""\ 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] """) 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("""\ 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)) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) 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}')) # 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, "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 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)) # 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, 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] """) 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("""\ 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)) """) 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)) """) expected_formatted_code = textwrap.dedent("""\ 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) """) expected_formatted_code = textwrap.dedent("""\ 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, } """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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)) 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}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ 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)) unformatted_code = textwrap.dedent("""\ 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)) 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() """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testBlankLinesAtEndOfFile(self): unformatted_code = textwrap.dedent("""\ def foobar(): # foo pass """) 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("""\ x = { 'a':37,'b':42, '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)) def testIndentBlankLines(self): 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 """ # noqa try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: yapf, indent_blank_lines: true}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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("""\ 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] """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) 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)) def testCommentsWithTrailingSpaces(self): unformatted_code = textwrap.dedent("""\ # Thing 1 \n# Thing 2 \n""") expected_formatted_code = textwrap.dedent("""\ # Thing 1 # Thing 2 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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. }) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testEndingWhitespaceAfterSimpleStatement(self): code = textwrap.dedent("""\ import foo as bar # Thing 1 # Thing 2 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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 ''') llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 ''') llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 ''') 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)) 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) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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] """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 ] """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testListComprehensionPreferOneLineOverArithmeticSplit(self): 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("""\ 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)) 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 ] """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 ] """) 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, )) """ 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)) 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) + " >" """ 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)) 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)) # 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) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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', }) """) # noqa 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', }) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineComment(self): code = textwrap.dedent("""\ if Foo: # Hello world # Yo man. # Yo man. # 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)) def testMultilineString(self): code = textwrap.dedent("""\ code = textwrap.dedent('''\ if Foo: # Hello world # Yo man. # Yo man. # Yo man. # Yo man. a = 42 ''') """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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"]+"""
""" ''') # 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.

Czar: """ + despot["Nicholas"] + """
Minion: """ + serf["Dmitri"] + """
Residence: """ + palace["Winter"] + """
""" ''') # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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,)) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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)) ''') # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testTrailingCommaAndBracket(self): unformatted_code = textwrap.dedent('''\ a = { 42, } b = ( 42, ) c = [ 42, ] ''') expected_formatted_code = textwrap.dedent('''\ a = { 42, } b = (42,) 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 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 llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testI18nCommentsInDataLiteral(self): code = textwrap.dedent("""\ def f(): return collections.OrderedDict({ #. First i18n comment. 'bork': 'foo', #. Second i18n comment. 'snork': 'bar#.*=\\\\0', }) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testClosingBracketIndent(self): code = textwrap.dedent('''\ def f(): def g(): while (xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and xxxxxxxxxxxxxxxxxxxxx( yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass ''') # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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, }) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) 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))] """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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 """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSpaceBetweenUnaryOpAndOpeningParen(self): code = textwrap.dedent("""\ if ~(a or b): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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) """) 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 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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))) """) 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 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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() """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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, ] """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 ] """) 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)) 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( ("...", "."), "..", "..............................................") """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testNoKeywordArgumentBreakage(self): code = textwrap.dedent("""\ class A(object): 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')) """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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" """) # 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 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 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testCommentsWithContinuationMarkers(self): code = textwrap.dedent("""\ def fn(arg): v = fn2(key1=True, #c1 key2=arg)\\ .fn3() """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultipleContinuationMarkers(self): code = textwrap.dedent("""\ xyz = \\ \\ some_thing() """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testContinuationMarkerAfterStringWithContinuation(self): code = """\ s = 'foo \\ bar' \\ .format() """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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.') """) # 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 expected_formatted_code = textwrap.dedent("""\ a = foo.bar({'xxxxxxxxxxxxxxxxxxxxxxx' 'yyyyyyyyyyyyyyyyyyyyyyyyyy': baz[42]} + 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' 'ddddddddddddddddddddddddddddd') """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) code = textwrap.dedent("""\ a = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa' \ 'bbbbbbbbbbbbbbbbbbbbbbbbbb' 'cccccccccccccccccccccccccccccccc' \ 'ddddddddddddddddddddddddddddd' """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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' """) 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) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingWithinSubscriptList(self): code = textwrap.dedent("""\ somequitelongvariablename.somemember[(a, b)] = { 'somelongkey': 1, 'someotherlongkey': 2 } """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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') ]) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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("""\ def _(): if True: if True: 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)) def testDictSetGenerator(self): code = textwrap.dedent("""\ foo = { variable: 'hello world. How are you today?' for variable in fnord if variable != 37 } """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnaryOpInDictionaryValue(self): code = textwrap.dedent("""\ beta = "123" test = {'alpha': beta[-1]} print(beta[-1]) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testRelaxArraySubscriptAffinity(self): 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 """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testFunctionCallInDict(self): 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" llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testUnbreakableNot(self): code = textwrap.dedent("""\ def test(): if not "Foooooooooooooooooooooooooooooo" or "Foooooooooooooooooooooooooooooo" == "Foooooooooooooooooooooooooooooo": pass """) # 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 ] """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testOverColumnLimit(self): unformatted_code = textwrap.dedent("""\ 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', } """) 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 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) )) """) 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 """) 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) """) 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 {} """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testNoSplittingBeforeEndingSubscriptBracket(self): 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("""\ 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)) 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)) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingArraysSensibly(self): unformatted_code = textwrap.dedent("""\ while True: while True: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list['bbbbbbbbbbbbbbbbbbbbbbbbb'].split(',') aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list('bbbbbbbbbbbbbbbbbbbbbbbbb').split(',') """) # noqa expected_formatted_code = textwrap.dedent("""\ while True: while True: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list[ 'bbbbbbbbbbbbbbbbbbbbbbbbb'].split(',') aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = list( 'bbbbbbbbbbbbbbbbbbbbbbbbb').split(',') """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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]) """) # 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 llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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)) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) 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 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) """) 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') ] """) 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),], ) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testMultilineLambdas(self): 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 """) # noqa 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 """) try: style.SetGlobalStyle( 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)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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 } """) # noqa 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 } """) # noqa try: style.SetGlobalStyle( 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)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testStableDictionaryFormatting(self): code = textwrap.dedent("""\ class A(object): def method(self): filters = { 'expressions': [{ 'field': { 'search_field': { 'user_field': 'latest_party__number_of_guests' }, } }] } """) # noqa try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: pep8, indent_width: 2, ' 'continuation_indent_width: 4, ' 'indent_dictionary_value: True}')) llines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, 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 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})) """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): url = "http://{0}/axis-cgi/admin/param.cgi?{1}".format( value, urllib.urlencode({ 'action': 'update', 'parameter': value })) """) 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) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testDontSplitKeywordValueArguments(self): 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)) """) 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) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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] """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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 ) """) # noqa 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}')) llines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, 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("""\ 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)) 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))) """) # noqa 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))) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 ) """) # noqa 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) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testSplittingArgumentsTerminatedByComma(self): 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,) """) # noqa 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, ) """) try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: yapf, ' 'split_arguments_when_comma_terminated: True}')) 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) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(expected_formatted_code, reformatted_code) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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), } """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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. ), } """) # noqa 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. ), } """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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}] """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDictionaryElementsOnOneLine(self): code = textwrap.dedent("""\ class _(): @mock.patch.dict( os.environ, {'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 more text yet again tex', } """) # 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 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 llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) 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 ''') llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) 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 ''') try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: yapf, ' 'blank_line_before_class_docstring: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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 ''') llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) 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 ''') try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: pep8, ' 'blank_line_before_module_docstring: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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')) """) 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 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') ] """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) 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, }, } """ 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("""\ 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: yapf, split_before_first_argument: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) 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("""\ 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: yapf, split_before_first_argument: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) 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("""\ 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: yapf, split_before_first_argument: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) 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("""\ 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: yapf, coalesce_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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: yapf, coalesce_brackets: True, ' 'dedent_closing_brackets: true}')) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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,] """) try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: yapf,' ' disable_ending_comma_heuristic: True}')) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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 """) # noqa 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 """) # noqa try: style.SetGlobalStyle( 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)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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 """) # noqa 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 """) # noqa try: style.SetGlobalStyle( 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)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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 """) # noqa 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 """) # noqa try: style.SetGlobalStyle( 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)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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 """) # noqa 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 """) # noqa try: style.SetGlobalStyle( 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)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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 """) # noqa 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: yapf,' ' indent_closing_brackets: True}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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 """) # noqa 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 """) # noqa try: style.SetGlobalStyle( 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)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testMultipleDictionariesInList(self): 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": [{ "12": "dd", "12345": "text 1" }, { "12": "ee", "12345": "text 2" }] } }] } """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testForceMultilineDict_True(self): try: style.SetGlobalStyle( 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("""\ responseDict = { 'childDict': { 'spam': 'eggs' } } """) self.assertCodeEqual(expected, actual) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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 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("""\ 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') """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected, reformatter.Reformat(llines)) if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/reformatter_buganizer_test.py000066400000000000000000002513041416201014000225600ustar00rootroot00000000000000# 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. """Buganizer tests for yapf.reformatter.""" import textwrap import unittest from yapf.yapflib import reformatter from yapf.yapflib import style from yapftests import yapf_test_helper class BuganizerFixes(yapf_test_helper.YAPFTest): @classmethod 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 """ 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] """ 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] """ 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 """ 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', ]), } """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB26521719(self): code = """\ class _(): 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 def _(): pass """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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 """ 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) """ 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) """ 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 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, } """ 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): def testNoAlertForShortPeriod(self, rutabaga): self.targets[:][ streamz_path, self._fillInOtherFields(streamz_path, {streamz_field_of_interest: True} )] = series.Counter('1s', '+ 500x10000') """ 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 """ 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 })) """ 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) """ 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) """ 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}) """ 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 """ 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 """ 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" }, { "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) """ 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 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 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 """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB65197969(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)) """ 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", ) """ 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]) """ 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 """ 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 ) """ 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'])))) """ 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) """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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}) """ 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))) """ 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. "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)) """ 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'))) """ 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( 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]) """ 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())) """ 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', ) """ 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() """ 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]) """ 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 + "-*")) """ 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' """) 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) ]] """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB36215507(self): code = textwrap.dedent("""\ class X(): def _(): aaaaaaaaaaaaa._bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb( mmmmmmmmmmmmm, nnnnn, ooooooooo, _(ppppppppppppppppppppppppppppppppppppp), *(qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq), **(qqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq)) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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') } } """) # noqa 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') } } """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB31063453(self): 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("""\ 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)) 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' }) """) # noqa 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' }) """) # 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 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)) 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]) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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', } } """) # noqa 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', } } """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB33047408(self): code = textwrap.dedent("""\ def _(): for sort in (sorts or []): request['sorts'].append({ 'field': { 'user_field': sort }, 'order': 'ASCENDING' }) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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, } """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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' } """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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: {}) """) # 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 """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB31847238(self): unformatted_code = textwrap.dedent("""\ class _(): 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. return 1 """) # noqa expected_formatted_code = textwrap.dedent("""\ class _(): 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. return 1 """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30760569(self): unformatted_code = textwrap.dedent("""\ {'1234567890123456789012345678901234567890123456789012345678901234567890': '1234567890123456789012345678901234567890'} """) # noqa expected_formatted_code = textwrap.dedent("""\ { '1234567890123456789012345678901234567890123456789012345678901234567890': '1234567890123456789012345678901234567890' } """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB26034238(self): 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("""\ class Thing: 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)) 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))) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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()) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 } } """) # noqa 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 } } """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB30173198(self): code = textwrap.dedent("""\ class _(): def _(): self.assertFalse( evaluation_runner.get_larps_in_eval_set('these_arent_the_larps')) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB29908765(self): code = textwrap.dedent("""\ class _(): def __repr__(self): return '' % ( self._id, self._stub._stub.rpc_channel().target()) # pylint:disable=protected-access """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB30087362(self): code = textwrap.dedent("""\ def _(): for s in sorted(env['foo']): bar() # This is a comment # This is another comment foo() """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB30087363(self): code = textwrap.dedent("""\ if False: bar() # This is a comment # This is another comment elif True: foo() """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB29093579(self): unformatted_code = textwrap.dedent("""\ def _(): _xxxxxxxxxxxxxxx(aaaaaaaa, bbbbbbbbbbbbbb.cccccccccc[ dddddddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) """) # noqa expected_formatted_code = textwrap.dedent("""\ def _(): _xxxxxxxxxxxxxxx( aaaaaaaa, bbbbbbbbbbbbbb.cccccccccc[dddddddddddddddddddddddddddd .eeeeeeeeeeeeeeeeeeeeee.fffffffffffffffffffff]) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB26382315(self): code = textwrap.dedent("""\ @hello_world # This is a first comment # Comment def foo(): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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), ]) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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) }) """) # noqa expected_formatted_code = textwrap.dedent("""\ if True: if True: self.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = ({ True: self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee), False: self.bbb.cccccccccc(ddddddddddddddddddddddd.eeeeeeeeeeeeeeeeeeeeee) }) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB27266946(self): unformatted_code = textwrap.dedent("""\ def _(): aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa = (self.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.cccccccccccccccccccccccccccccccccccc) """) # 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)) def testB25505359(self): code = textwrap.dedent("""\ _EXAMPLE = { 'aaaaaaaaaaaaaa': [{ 'bbbb': 'cccccccccccccccccccccc', 'dddddddddddd': [] }, { 'bbbb': 'ccccccccccccccccccc', 'dddddddddddd': [] }] } """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25324261(self): code = textwrap.dedent("""\ 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)) def testB25136704(self): code = textwrap.dedent("""\ class f: 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)) 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 llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB25157123(self): code = textwrap.dedent("""\ 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)) 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', }) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 }) """) # noqa 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 }) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23445244(self): unformatted_code = textwrap.dedent("""\ def foo(): if True: return xxxxxxxxxxxxxxxx( command, extra_env={ "OOOOOOOOOOOOOOOOOOOOO": FLAGS.zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, "PPPPPPPPPPPPPPPPPPPPP": FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, }) """) # noqa expected_formatted_code = textwrap.dedent("""\ def foo(): if True: return xxxxxxxxxxxxxxxx( command, extra_env={ "OOOOOOOOOOOOOOOOOOOOO": FLAGS.zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz, "PPPPPPPPPPPPPPPPPPPPP": FLAGS.aaaaaaaaaaaaaa + FLAGS.bbbbbbbbbbbbbbbbbbb, }) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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' } }) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20551180(self): unformatted_code = textwrap.dedent("""\ def foo(): if True: return (struct.pack('aaaa', bbbbbbbbbb, ccccccccccccccc, dddddddd) + eeeeeee) """) # 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)) def testB23944849(self): 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("""\ class A(object): def xxxxxxxxx(self, aaaaaaa, bbbbbbb=ccccccccccc, dddddd=300, eeeeeeeeeeeeee=None, fffffffffffffff=0): pass """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB23935890(self): unformatted_code = textwrap.dedent("""\ class F(): def functioni(self, aaaaaaa, bbbbbbb, cccccc, dddddddddddddd, eeeeeeeeeeeeeee): pass """) # 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)) 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])) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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])) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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) """) try: style.SetGlobalStyle( style.CreateStyleFromConfig( '{based_on_style: pep8, split_penalty_import_names: 350}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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)) """) # noqa try: style.SetGlobalStyle( style.CreateStyleFromConfig('{based_on_style: yapf, ' 'split_before_logical_operator: True}')) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) def testB22527411(self): unformatted_code = textwrap.dedent("""\ def f(): if True: aaaaaa.bbbbbbbbbbbbbbbbbbbb[-1].cccccccccccccc.ddd().eeeeeeee(ffffffffffffff) """) # 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)) def testB20849933(self): unformatted_code = textwrap.dedent("""\ def main(unused_argv): if True: aaaaaaaa = { 'xxx': '%s/cccccc/ddddddddddddddddddd.jar' % (eeeeee.FFFFFFFFFFFFFFFFFF), } """) expected_formatted_code = textwrap.dedent("""\ def main(unused_argv): if True: aaaaaaaa = { 'xxx': '%s/cccccc/ddddddddddddddddddd.jar' % (eeeeee.FFFFFFFFFFFFFFFFFF), } """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB20813997(self): code = textwrap.dedent("""\ def myfunc_1(): myarray = numpy.zeros((2, 2, 2)) print(myarray[:, 1, :]) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20605036(self): code = textwrap.dedent("""\ foo = { 'aaaa': { # A comment for no particular reason. 'xxxxxxxx': 'bbbbbbbbb', 'yyyyyyyyyyyyyyyyyy': 'cccccccccccccccccccccccccccccc' 'dddddddddddddddddddddddddddddddddddddddddd', } } """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20562732(self): code = textwrap.dedent("""\ foo = [ # Comment about first list item 'First item', # Comment about second list item 'Second item', ] """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB20128830(self): code = textwrap.dedent("""\ a = { 'xxxxxxxxxxxxxxxxxxxx': { 'aaaa': 'mmmmmmm', 'bbbbb': 'mmmmmmmmmmmmmmmmmmmmm', 'cccccccccc': [ 'nnnnnnnnnnn', 'ooooooooooo', 'ppppppppppp', 'qqqqqqqqqqq', ], }, } """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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)) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19626808(self): code = textwrap.dedent("""\ if True: aaaaaaaaaaaaaaaaaaaaaaa.bbbbbbbbb( 'ccccccccccc', ddddddddd='eeeee').fffffffff([ggggggggggggggggggggg]) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB19377034(self): code = textwrap.dedent("""\ 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)) def testB19372573(self): code = textwrap.dedent("""\ def f(): if a: return 42 while True: if b: continue if c: break return 0 """) try: style.SetGlobalStyle(style.CreatePEP8Style()) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreateYapfStyle()) 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)) 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) """) # noqa 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) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB19194420(self): code = textwrap.dedent("""\ 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 })) """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18257115(self): code = textwrap.dedent("""\ if True: 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)) 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) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testB18255697(self): code = textwrap.dedent("""\ AAAAAAAAAAAAAAA = { 'XXXXXXXXXXXXXX': 4242, # Inline comment # Next comment 'YYYYYYYYYYYYYYYY': ['zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz'], } """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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)})) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 } """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testB16783631(self): unformatted_code = textwrap.dedent("""\ if True: with aaaaaaaaaaaaaa.bbbbbbbbbbbbb.ccccccc(ddddddddddddd, eeeeeeeee=self.fffffffffffff )as gggg: pass """) # 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)) 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') """) # noqa 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') """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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]) """) # noqa 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]) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 what's too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] """) # noqa 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 what's too long, etc." + " no really ")[:ARBITRARY_CONSTANT_A] """) # 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) """ 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 expected_formatted_code = textwrap.dedent("""\ aaaaaaaaaaaa = bbbb.ccccccccccccccc(dddddd.eeeeeeeeeeeeee, ffffffffffffffffff, gggggg.hhhhhhhhhhhhhhhhh) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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) """) # noqa 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) """) # 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, ) """ llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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)) """) 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 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 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 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("""\ 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)) def testB67935687(self): code = textwrap.dedent("""\ Fetch( Raw('monarch.BorgTask', '/union/row_operator_action_delay'), {'borg_user': self.borg_user}) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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}) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/reformatter_facebook_test.py000066400000000000000000000355451416201014000223520ustar00rootroot00000000000000# 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. """Facebook tests for yapf.reformatter.""" import textwrap import unittest from yapf.yapflib import reformatter from yapf.yapflib import style from yapftests import yapf_test_helper class TestsForFacebookStyle(yapf_test_helper.YAPFTest): @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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentImportAsNames(self): code = textwrap.dedent("""\ from module import ( internal_function as function, SOME_CONSTANT_NUMBER1, SOME_CONSTANT_NUMBER2, SOME_CONSTANT_NUMBER3, ) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testDedentTestListGexp(self): 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 """) 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 """) 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. pass0_code = textwrap.dedent("""\ try: pass except (IOError, OSError, LookupError, RuntimeError, OverflowError) as exception: pass """) # noqa pass1_code = textwrap.dedent("""\ try: pass except ( IOError, OSError, LookupError, RuntimeError, OverflowError ) as exception: pass """) llines = yapf_test_helper.ParseAndUnwrap(pass0_code) self.assertCodeEqual(pass1_code, reformatter.Reformat(llines)) pass2_code = textwrap.dedent("""\ try: pass except ( IOError, OSError, LookupError, RuntimeError, OverflowError ) as exception: pass """) llines = yapf_test_helper.ParseAndUnwrap(pass1_code) self.assertCodeEqual(pass2_code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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( result.reason_not_added, "current preflight is still running" ) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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) """) # noqa 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 ) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testDedentingCallsWithInnerLists(self): code = textwrap.dedent("""\ class _(): def _(): cls.effect_clues = { 'effect': Clue((cls.effect_time, 'apache_host'), effect_line, 40) } """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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) ] """) # noqa 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) ] """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMustSplitDedenting(self): code = textwrap.dedent("""\ class _(): def _(): effect_line = FrontInput( effect_line_offset, line_content, LineSource('localhost', xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) ) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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), ] ) """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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 ) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(code) reformatted_code = reformatter.Reformat(llines) self.assertCodeEqual(code, 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("""\ def foo(): if 0: return False #a deadly comment elif 1: return True print(foo()) """) expected_formatted_code = textwrap.dedent("""\ def foo(): if 0: return False #a deadly comment elif 1: return True 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 """ llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/reformatter_pep8_test.py000066400000000000000000001014351416201014000214450ustar00rootroot00000000000000# 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. """PEP8 tests for yapf.reformatter.""" 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 class TestsForPEP8Style(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): # pylint: disable=g-missing-super-call style.SetGlobalStyle(style.CreatePEP8Style()) 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)) def testSingleLineIfStatements(self): code = textwrap.dedent("""\ if True: a = 42 elif False: b = 42 else: c = 42 """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testBlankBetweenClassAndDef(self): unformatted_code = textwrap.dedent("""\ 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)) def testBlankBetweenDefsInClass(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 ''') llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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)) def testSpaceBetweenEndingCommandAndClosingBracket(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)) def testContinuedNonOutdentedLine(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') """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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) """) # noqa 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) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 ) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) unformatted_code = textwrap.dedent("""\ def f(): def g(): while (xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb' ): pass """) # noqa expected_formatted_code = textwrap.dedent("""\ def f(): def g(): while (xxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and xxxxxxxxxxxxxxxxxxxx( yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 - program_start_time).total_seconds() / 60.0 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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) """) # noqa 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) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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) """) # noqa 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) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) def testContiguousListEndingWithComment(self): unformatted_code = textwrap.dedent("""\ 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 llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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) """) # 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)) finally: style.SetGlobalStyle(style.CreatePEP8Style()) 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') & (df['action_status'] == 'LIVE')] """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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", ] """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 ) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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."), } """) # noqa 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." ), } """) # 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 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 llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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("""\ attrs = { 'category': category, 'role': forms.ModelChoiceField( label=_("Role"), required=False, queryset=category_roles, initial=selected_role, empty_label=_("No access"), ), } """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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("""\ css_class = forms.CharField( label=_("CSS class"), required=False, help_text=_( "Optional CSS class used to customize this category appearance from templates." ), ) """) # noqa llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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)) """ 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 """ ''' llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertEqual(expected_code, reformatter.Reformat(llines)) 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)) """ # noqa expected_formatted_code = """\ 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)) 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)]) """ llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_code, reformatter.Reformat(llines)) 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 ''' 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("""\ 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testParamListIndentationCollision2(self): code = textwrap.dedent("""\ 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)) def testParamListIndentationCollision3(self): code = textwrap.dedent("""\ def func1( arg1, arg2, ) -> None: pass def func2( arg1, arg2, ): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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) _ = (klsdfjdklsfjksdlfjdklsfjdslkfjsdkl not in {ksldfjsdklfjdklsfjdklsfjdklsfjdsklfjdklsfj}) """) 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 _(): 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( value, urllib.urlencode({ 'action': 'update', 'parameter': value })) """) 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) 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("""\ 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, 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)) @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("""\ 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] """) 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,' '}')) 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 ] """) 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("""\ 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)) if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/reformatter_python3_test.py000066400000000000000000000340231416201014000221730ustar00rootroot00000000000000# 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. """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 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.""" @classmethod def setUpClass(cls): # pylint: disable=g-missing-super-call 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 """) # noqa expected_formatted_code = textwrap.dedent("""\ def x(aaaaaaaaaaaaaaa: int, bbbbbbbbbbbbbbbb: str, ccccccccccccccc: dict, eeeeeeeeeeeeee: set = {1, 2, 3}) -> bool: pass """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) 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: return a+b """) expected_formatted_code = textwrap.dedent("""\ def foo(a: list, b: "bar") -> dict: return a + b """) 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' 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("""\ 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(code) self.assertCodeEqual(code, reformatter.Reformat(llines, 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}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) finally: 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}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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 """) 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 """) 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 = """\ None.__ne__() """ llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testAsyncFunctionsNested(self): if sys.version_info[1] < 5: return code = textwrap.dedent("""\ async def outer(): async def inner(): pass """) llines = yapf_test_helper.ParseAndUnwrap(code) 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[ automation_converter.PyiCollectionAbc]: pass """) # noqa expected_formatted_code = textwrap.dedent("""\ def _ReduceAbstractContainers( self, *args: Optional[automation_converter.PyiCollectionAbc] ) -> List[automation_converter.PyiCollectionAbc]: pass """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) 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( 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) 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 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 """ 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}')) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) 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 = """\ class Foo: def foo(self): foofoofoofoofoofoofoofoo('foofoofoofoofoo', { 'foo': 'foo', **foofoofoo }) """ expected_formatted_code = """\ class Foo: def foo(self): foofoofoofoofoofoofoofoo('foofoofoofoofoo', { 'foo': 'foo', **foofoofoo }) """ llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testMultilineFormatString(self): if sys.version_info[1] < 6: return code = """\ # yapf: disable (f''' ''') # yapf: enable """ # https://github.com/google/yapf/issues/513 llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) def testEllipses(self): if sys.version_info[1] < 6: return code = """\ def dirichlet(x12345678901234567890123456789012345678901234567890=...) -> None: return """ # https://github.com/google/yapf/issues/533 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 """ 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 """ llines = yapf_test_helper.ParseAndUnwrap(code) 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: for i in range(10): pass else: pass else: pass """) llines = yapf_test_helper.ParseAndUnwrap(code) 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): pass else: pass """) llines = yapf_test_helper.ParseAndUnwrap(code) self.assertCodeEqual(code, reformatter.Reformat(llines)) 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 """) # noqa 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 """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/reformatter_style_config_test.py000066400000000000000000000160571416201014000232630ustar00rootroot00000000000000# 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. """Style config tests for yapf.reformatter.""" import textwrap import unittest from yapf.yapflib import reformatter from yapf.yapflib import style from yapftests import yapf_test_helper class TestsForStyleConfig(yapf_test_helper.YAPFTest): def setUp(self): self.current_style = style.DEFAULT_STYLE def testSetGlobalStyle(self): try: style.SetGlobalStyle(style.CreateYapfStyle()) 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') """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) 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') """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) self.assertCodeEqual(expected_formatted_code, reformatter.Reformat(llines)) def testOperatorNoSpaceStyle(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 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, 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['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) 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 k = (1 * 2 * 3) + (4 * 5 * 6 * 7 * 8) """) 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) 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 k = (1*2*3) + (4*5*6*7*8) """) llines = yapf_test_helper.ParseAndUnwrap(unformatted_code) 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['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") """) # noqa 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 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") """) 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 if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/reformatter_verify_test.py000066400000000000000000000062271416201014000221000ustar00rootroot00000000000000# 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() yapf-0.32.0/yapftests/split_penalty_test.py000066400000000000000000000163711416201014000210520ustar00rootroot00000000000000# 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. """Tests for yapf.split_penalty.""" import sys import textwrap import unittest from lib2to3 import pytree 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 DOTTED_NAME = split_penalty.DOTTED_NAME STRONGLY_CONNECTED = split_penalty.STRONGLY_CONNECTED class SplitPenaltyTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): style.SetGlobalStyle(style.CreateYapfStyle()) def _ParseAndComputePenalties(self, code, dumptree=False): """Parses the code and computes split penalties. Arguments: code: code to parse as a string dumptree: if True, the parsed pytree (after penalty assignment) is dumped to stderr. Useful for debugging. Returns: Parse tree. """ tree = pytree_utils.ParseCodeToTree(code) split_penalty.ComputeSplitPenalties(tree) if dumptree: pytree_visitor.DumpPyTree(tree, target_stream=sys.stderr) return tree def _CheckPenalties(self, tree, list_of_expected): """Check that the tokens in the tree have the correct penalties. Args: tree: the pytree. list_of_expected: list of (name, penalty) pairs. Non-semantic tokens are filtered out from the expected values. """ 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))] nodes = [] for node in tree.children: nodes += FlattenRec(node) return nodes self.assertEqual(list_of_expected, FlattenRec(tree)) def testUnbreakable(self): # Test function definitions. code = textwrap.dedent(r""" def foo(x): pass """) tree = self._ParseAndComputePenalties(code) 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""" 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), ]) # Test class definitions. 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), ]) # 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), ]) # 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), ]) def testStronglyConnected(self): # Test dictionary keys. 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), ]) # 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), ]) 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), ]) # 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), ]) # 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() yapf-0.32.0/yapftests/style_test.py000066400000000000000000000264731416201014000173270ustar00rootroot00000000000000# -*- coding: utf-8 -*- # 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. """Tests for yapf.style.""" import os import shutil import tempfile import textwrap import unittest from yapf.yapflib import style from yapftests import utils from yapftests import yapf_test_helper class UtilsTest(yapf_test_helper.YAPFTest): def testContinuationAlignStyleStringConverter(self): 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'", str(ctx.exception)) def testStringListConverter(self): self.assertEqual(style._StringListConverter('foo, bar'), ['foo', 'bar']) self.assertEqual(style._StringListConverter('foo,bar'), ['foo', 'bar']) self.assertEqual(style._StringListConverter(' foo'), ['foo']) self.assertEqual( style._StringListConverter('joe ,foo, bar'), ['joe', 'foo', 'bar']) def testBoolConverter(self): self.assertEqual(style._BoolConverter('true'), True) self.assertEqual(style._BoolConverter('1'), True) 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 _LooksLikeGoogleStyle(cfg): return cfg['COLUMN_LIMIT'] == 80 and cfg['SPLIT_COMPLEX_COMPREHENSION'] def _LooksLikePEP8Style(cfg): return cfg['COLUMN_LIMIT'] == 79 def _LooksLikeFacebookStyle(cfg): return cfg['DEDENT_CLOSING_BRACKETS'] def _LooksLikeYapfStyle(cfg): return cfg['SPLIT_BEFORE_DOT'] class PredefinedStylesByNameTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): # pylint: disable=g-missing-super-call 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 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'): cfg = style.CreateStyleFromConfig(fb_name) self.assertTrue(_LooksLikeFacebookStyle(cfg)) class StyleFromFileTest(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): # pylint: disable=g-missing-super-call cls.test_tmpdir = tempfile.mkdtemp() style.SetGlobalStyle(style.CreatePEP8Style()) @classmethod def tearDownClass(cls): # pylint: disable=g-missing-super-call shutil.rmtree(cls.test_tmpdir) def testDefaultBasedOnStyle(self): cfg = textwrap.dedent(u'''\ [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(u'''\ [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(u'''\ [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(u'''\ [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(u'''\ [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)) 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 = pep8 I18N_FUNCTION_CALL = N_, V_, T_ ''') with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: cfg = style.CreateStyleFromConfig(filepath) self.assertTrue(_LooksLikePEP8Style(cfg)) self.assertEqual(cfg['I18N_FUNCTION_CALL'], ['N_', 'V_', 'T_']) def testErrorNoStyleFile(self): with self.assertRaisesRegex(style.StyleConfigError, 'is not a valid style or file path'): style.CreateStyleFromConfig('/8822/xyznosuchfile') def testErrorNoStyleSection(self): cfg = textwrap.dedent(u'''\ [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(u'''\ [style] indent_width=2 hummus=2 ''') with utils.TempFileContents(self.test_tmpdir, cfg) as filepath: with self.assertRaisesRegex(style.StyleConfigError, 'Unknown style option'): 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.assertRaisesRegex(style.StyleConfigError, 'Unable to find section'): style.CreateStyleFromConfig(filepath) def testPyprojectTomlParseYapfSection(self): try: import toml except ImportError: return 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(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): # pylint: disable=g-missing-super-call 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(_LooksLikePEP8Style(cfg)) 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'}) class StyleFromCommandLine(yapf_test_helper.YAPFTest): @classmethod def setUpClass(cls): # pylint: disable=g-missing-super-call style.SetGlobalStyle(style.CreatePEP8Style()) def testDefaultBasedOnStyle(self): cfg = style.CreateStyleFromConfig( '{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) def testDefaultBasedOnStyleNotStrict(self): cfg = style.CreateStyleFromConfig( '{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) 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.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): def testHelpKeys(self): settings = sorted(style.Help()) expected = sorted(style._style) self.assertListEqual(settings, expected) if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/subtype_assigner_test.py000066400000000000000000000222341416201014000215440ustar00rootroot00000000000000# 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. """Tests for yapf.subtype_assigner.""" import textwrap import unittest from yapf.yapflib import format_token from yapf.yapflib import pytree_utils from yapf.yapflib import subtypes from yapftests import yapf_test_helper class SubtypeAssignerTest(yapf_test_helper.YAPFTest): def _CheckFormatTokenSubtypes(self, llines, list_of_expected): """Check that the tokens in the LogicalLines have the expected subtypes. Args: llines: list of LogicalLine. list_of_expected: list of (name, subtype) pairs. Non-semantic tokens are filtered out from the expected values. """ 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] if filtered_values: actual.append(filtered_values) self.assertEqual(list_of_expected, actual) def testFuncDefDefaultAssign(self): self.maxDiff = None # pylint: disable=invalid-name 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}), ], ]) def testFuncCallWithDefaultAssign(self): 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}), ], ]) def testSetComprehension(self): 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}), ], ]) def testUnaryNotOperator(self): code = textwrap.dedent("""\ not a """) llines = yapf_test_helper.ParseAndUnwrap(code) self._CheckFormatTokenSubtypes(llines, [[('not', {subtypes.UNARY_OPERATOR}), ('a', {subtypes.NONE})]]) def testBitwiseOperators(self): 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}), ], ]) def testArithmeticOperators(self): 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}), ], ]) def testSubscriptColon(self): 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}), ], ]) def testFunctionCallWithStarExpression(self): 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}), ], ]) if __name__ == '__main__': unittest.main() yapf-0.32.0/yapftests/utils.py000066400000000000000000000052241416201014000162570ustar00rootroot00000000000000# -*- coding: utf-8 -*- # 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. """Utilities for tests.""" import contextlib import io import os import sys import tempfile @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 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 documentation. @contextlib.contextmanager 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: suffix = '' if prefix is None: prefix = 'tmp' (fd, fname) = tempfile.mkstemp( suffix=suffix, prefix=prefix, dir=dirname, 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( dirname=dirname, mode='w', encoding=encoding, newline=newline, suffix=suffix) as (f, fname): f.write(contents) f.flush() yield fname yapf-0.32.0/yapftests/yapf_test.py000066400000000000000000001727521416201014000171300ustar00rootroot00000000000000# -*- coding: utf-8 -*- # 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. """Tests for yapf.yapf.""" import io import logging import os import shutil import subprocess import sys import tempfile import textwrap import unittest 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 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'] class FormatCodeTest(yapf_test_helper.YAPFTest): def _Check(self, unformatted_code, expected_formatted_code): formatted_code, _ = yapf_api.FormatCode( unformatted_code, style_config='yapf') self.assertCodeEqual(expected_formatted_code, formatted_code) def testSimple(self): unformatted_code = textwrap.dedent("""\ print('foo') """) self._Check(unformatted_code, unformatted_code) def testNoEndingNewline(self): unformatted_code = textwrap.dedent("""\ if True: pass""") expected_formatted_code = textwrap.dedent("""\ if True: pass """) 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 self.test_tmpdir = tempfile.mkdtemp() 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(u"""\ if True: pass """) expected_formatted_code_pep8 = textwrap.dedent(u"""\ if True: pass """) expected_formatted_code_yapf = textwrap.dedent(u"""\ 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) 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"""\ if a: b # yapf: disable if f: g if h: i """) expected_formatted_code = textwrap.dedent(u"""\ if a: b # yapf: disable 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) def testDisableAndReenableLinesPattern(self): unformatted_code = textwrap.dedent(u"""\ if a: b # yapf: disable if f: g # yapf: enable if h: i """) expected_formatted_code = textwrap.dedent(u"""\ if a: b # yapf: disable if f: g # 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) def testDisablePartOfMultilineComment(self): unformatted_code = textwrap.dedent(u"""\ if a: b # This is a multiline comment that disables YAPF. # yapf: disable if f: g # yapf: enable # This is a multiline comment that enables YAPF. if h: i """) expected_formatted_code = textwrap.dedent(u"""\ if a: b # This is a multiline comment that disables YAPF. # yapf: disable if f: g # yapf: enable # 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) code = textwrap.dedent(u"""\ def foo_function(): # some comment # yapf: disable foo( bar, baz ) # 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 testEnabledDisabledSameComment(self): code = textwrap.dedent(u"""\ # yapf: disable a(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, ccccccccccccccccccccccccccccccc, ddddddddddddddddddddddd, eeeeeeeeeeeeeeeeeeeeeeeeeee) # yapf: enable # 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) def testFormatFileLinesSelection(self): unformatted_code = textwrap.dedent(u"""\ if a: b if f: g if h: i """) expected_formatted_code_lines1and2 = textwrap.dedent(u"""\ if a: b if f: g if h: i """) expected_formatted_code_lines3 = textwrap.dedent(u"""\ 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)]) 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(u"""\ 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) def testFormatFileInPlace(self): unformatted_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) 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() 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") def testCommentsUnformatted(self): code = textwrap.dedent(u"""\ foo = [# A list of things # bork '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) def testDisabledHorizontalFormattingOnNewLine(self): code = textwrap.dedent(u"""\ # yapf: disable 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) 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 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) def testDisabledMultilineStringInDictionary(self): code = textwrap.dedent(u"""\ # yapf: disable A = [ { "aaaaaaaaaaaaaaaaaaa": ''' bbbbbbbbbbb: "ccccccccccc" dddddddddddddd: 1 eeeeeeee: 0 ffffffffff: "ggggggg" ''', }, ] """) with utils.TempFileContents(self.test_tmpdir, code) as filepath: formatted_code, _, _ = yapf_api.FormatFile(filepath, style_config='yapf') self.assertCodeEqual(code, formatted_code) def testDisabledWithPrecedingText(self): code = textwrap.dedent(u"""\ # TODO(fix formatting): yapf: disable A = [ { "aaaaaaaaaaaaaaaaaaa": ''' bbbbbbbbbbb: "ccccccccccc" dddddddddddddd: 1 eeeeeeee: 0 ffffffffff: "ggggggg" ''', }, ] """) with utils.TempFileContents(self.test_tmpdir, code) as filepath: 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='yapf') self.assertCodeEqual(code, formatted_code) class CommandLineTest(unittest.TestCase): """Test how calling yapf from the command line acts.""" @classmethod def setUpClass(cls): # pylint: disable=g-missing-super-call cls.test_tmpdir = tempfile.mkdtemp() @classmethod def tearDownClass(cls): # pylint: disable=g-missing-super-call shutil.rmtree(cls.test_tmpdir) 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. Checks that the formatted output is as expected. Arguments: 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, env=env) reformatted_code, stderrdata = p.communicate( unformatted.encode('utf-8-sig')) 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(): 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 testInPlaceReformattingBlank(self): unformatted_code = u'\n\n' expected_formatted_code = u'\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 testInPlaceReformattingEmpty(self): unformatted_code = u'' expected_formatted_code = u'' 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 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, extra_options=['--style=yapf']) 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(u'''\ [style] based_on_style = yapf 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 """) # noqa style_file = textwrap.dedent(u'''\ [style] spaces_before_comment = 15, 20 ''') with utils.TempFileContents(self.test_tmpdir, style_file) as stylepath: self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--style={0}'.format(stylepath)]) 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): 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: try: 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 # noqa def testReformattingSpecificLines(self): unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass 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 xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass 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. self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--lines', '1-2']) def testOmitFormattingLinesBeforeDisabledFunctionComment(self): unformatted_code = textwrap.dedent("""\ import sys # 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, extra_options=['--lines', '5-5']) def testReformattingSkippingLines(self): unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass # yapf: disable 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 xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass # yapf: disable 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): unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass # yapf: disable def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass def f(): def e(): while (xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass """) # noqa expected_formatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass # yapf: disable def g(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass def f(): def e(): while (xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz]) == 'aaaaaaaaaaa' and xxxxxxxxxxxxxxxxxxxxx(yyyyyyyyyyyyy[zzzzz].aaaaaaaa[0]) == 'bbbbbbb'): pass """) # noqa self.assertYapfReformats(unformatted_code, expected_formatted_code) def testReformattingSkippingSingleLine(self): unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass 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 xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass 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): unformatted_code = textwrap.dedent("""\ A = set([ '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): 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 """) self.assertYapfReformats(unformatted_code, expected_formatted_code) def testRetainingHorizontalWhitespace(self): unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass 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 xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass 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): unformatted_code = textwrap.dedent("""\ def h(): if (xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0]) == 'aaaaaaaaaaa' and xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass 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 xxxxxxxxxxxx.yyyyyyyy(zzzzzzzzzzzzz[0].mmmmmmmm[0]) == 'bbbbbbb'): pass 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, extra_options=['--lines', '1-2']) unformatted_code = textwrap.dedent("""\ if a: b if c: to_much + indent same #comment # trailing whitespace """) expected_formatted_code = textwrap.dedent("""\ if a: b if c: to_much + indent same #comment # trailing whitespace """) self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--lines', '3-3', '--lines', '13-13']) unformatted_code = textwrap.dedent("""\ ''' docstring ''' import blah """) 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 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, extra_options=['--lines', '1-1']) def testDisabledMultilineStrings(self): 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.

Czar: """+despot["Nicholas"]+"""
Minion: """+serf["Dmitri"]+"""
Residence: """+palace["Winter"]+"""
""" ''') # noqa 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"]+"""
Minion: """+serf["Dmitri"]+"""
Residence: """+palace["Winter"]+"""
""" ''') # noqa self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--lines', '1-1']) def testDisableWhenSpecifyingLines(self): unformatted_code = textwrap.dedent("""\ # yapf: disable A = set([ 'hello', 'world', ]) # yapf: enable B = set([ 'hello', 'world', ]) # yapf: disable """) expected_formatted_code = textwrap.dedent("""\ # yapf: disable A = set([ 'hello', 'world', ]) # yapf: enable B = set([ 'hello', 'world', ]) # yapf: disable """) self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--lines', '1-10']) def testDisableFormattingInDataLiteral(self): unformatted_code = textwrap.dedent("""\ def horrible(): oh_god() why_would_you() [ 'do', 'that', ] def still_horrible(): oh_god() why_would_you() [ 'do', 'that' ] """) expected_formatted_code = textwrap.dedent("""\ def horrible(): oh_god() why_would_you() [ 'do', 'that', ] def still_horrible(): oh_god() why_would_you() ['do', 'that'] """) self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--lines', '14-15']) def testRetainVerticalFormattingBetweenDisabledAndEnabledLines(self): unformatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) self.assertEqual( ('ddddddddddddddddddddddddd', 'eeeeeeeeeeeeeeeeeeeeeeeee.%s' % c.ffffffffffff), gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii """) expected_formatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) self.assertEqual(('ddddddddddddddddddddddddd', 'eeeeeeeeeeeeeeeeeeeeeeeee.%s' % c.ffffffffffff), gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii """) # noqa self.assertYapfReformats( unformatted_code, 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): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) self.assertEqual( ('ddddddddddddddddddddddddd', 'eeeeeeeeeeeeeeeeeeeeeeeee.%s' % c.ffffffffffff), gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii """) expected_formatted_code = textwrap.dedent("""\ class A(object): def aaaaaaaaaaaaa(self): c = bbbbbbbbb.ccccccccc('challenge', 0, 1, 10) self.assertEqual(('ddddddddddddddddddddddddd', 'eeeeeeeeeeeeeeeeeeeeeeeee.%s' % c.ffffffffffff), gggggggggggg.hhhhhhhhh(c, c.ffffffffffff)) iiiii = jjjjjjjjjjjjjj.iiiii """) # noqa self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--lines', '5-6']) def testCommentFollowingMultilineString(self): unformatted_code = textwrap.dedent("""\ def foo(): '''First line. Second line. ''' # comment x = '''hello world''' # second comment return 42 # another comment """) expected_formatted_code = textwrap.dedent("""\ def foo(): '''First line. Second line. ''' # comment x = '''hello world''' # second comment return 42 # another comment """) self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--lines', '1-1']) 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): pass """) self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--style=pep8']) # TODO(ambv): currently the following produces the closing bracket on a new # line but indented to the opening bracket which is the worst of both # worlds. Expected behaviour would be to format as --style=pep8 does in # this case. # self.assertYapfReformats(unformatted_code, expected_formatted_code, # extra_options=['--style=facebook']) # 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 """) # 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 ): pass """) # noqa self.assertYapfReformats( unformatted_code, expected_formatted_fb_code, extra_options=['--style=facebook']) # TODO(ambv): currently the following produces code that is not PEP8 # compliant, raising "E125 continuation line with same indent as next # logical line" with flake8. Expected behaviour for PEP8 would be to use # double-indentation here. # self.assertYapfReformats(unformatted_code, expected_formatted_pep8_code, # extra_options=['--style=pep8']) 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" } )""") 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(u'''\ [style] column_limit=82 coalesce_brackets = True ''')) f.flush() self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--style={0}'.format(name)]) def testPseudoParenSpaces(self): unformatted_code = textwrap.dedent("""\ 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, extra_options=['--lines', '1-1', '--style', 'yapf']) def testMultilineCommentFormattingDisabled(self): unformatted_code = textwrap.dedent("""\ # This is a comment FOO = { aaaaaaaa.ZZZ: [ bbbbbbbbbb.Pop(), # Multiline comment. # Line two. bbbbbbbbbb.Pop(), ], 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx': ('yyyyy', zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz), '#': lambda x: x # do nothing } """) expected_formatted_code = textwrap.dedent("""\ # This is a comment FOO = { aaaaaaaa.ZZZ: [ bbbbbbbbbb.Pop(), # Multiline comment. # Line two. bbbbbbbbbb.Pop(), ], 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx': ('yyyyy', zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz), '#': lambda x: x # do nothing } """) self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--lines', '1-1', '--style', 'yapf']) def testTrailingCommentsWithDisabledFormatting(self): unformatted_code = textwrap.dedent("""\ import os 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 """ expected_formatted_code = """\ def foo_function(): if True: pass """ # noqa: W191,E101 style_contents = u"""\ [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, 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', ] """ # noqa: W191,E101 style_contents = u"""\ [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, 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', ] """ # noqa: W191,E101 style_contents = u"""\ [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, 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', ] """ # noqa: W191,E101 style_contents = u"""\ [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, 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 = 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, 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 = 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, 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 utils.NamedTempFile(dirname=self.test_tmpdir) as (stylefile, stylepath): p = subprocess.Popen( YAPF_BINARY + ['--style-help'], stdout=stylefile, stdin=subprocess.PIPE, stderr=subprocess.PIPE) _, stderrdata = p.communicate() self.assertEqual(stderrdata, b'') self.assertYapfReformats( unformatted_code, 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']) 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', '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 = """\ 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 a = [ 1, 2, 3 ] """ expected_formatted_code = """\ # yapf: disable a = [ 1, 2, 3 ] """ self.assertYapfReformats( unformatted_code, expected_formatted_code, extra_options=['--style', 'yapf', '--lines', '1-100']) class BadInputTest(unittest.TestCase): """Test yapf's behaviour when passed bad input.""" def testBadSyntax(self): code = ' a = 1\n' self.assertRaises(errors.YapfError, yapf_api.FormatCode, code) def testBadCode(self): code = 'x = """hello\n' self.assertRaises(errors.YapfError, yapf_api.FormatCode, code) class DiffIndentTest(unittest.TestCase): @staticmethod def _OwnStyle(): 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._OwnStyle())) self.assertEqual(expected_formatted_code, formatted_code) 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) class HorizontallyAlignedTrailingCommentsTest(yapf_test_helper.YAPFTest): @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.assertCodeEqual(expected_formatted_code, formatted_code) 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 # 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 # 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 """) # noqa 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 """) # noqa 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 """) # 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 # 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 """) # noqa 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) 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) 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() yapf-0.32.0/yapftests/yapf_test_helper.py000066400000000000000000000057321416201014000204600ustar00rootroot00000000000000# 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. """Support module for tests for yapf.""" import difflib import sys 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 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 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:'] linelen = style.Get('COLUMN_LIMIT') for line in expected_code.splitlines(): if len(line) > linelen: msg.append('!> %s' % line) else: msg.append(' > %s' % line) msg.append('Actual:') for line in code.splitlines(): if len(line) > linelen: msg.append('!> %s' % line) else: msg.append(' > %s' % line) msg.append('Diff:') msg.extend( difflib.unified_diff( code.splitlines(), expected_code.splitlines(), fromfile='actual', tofile='expected', lineterm='')) self.fail('\n'.join(msg)) def ParseAndUnwrap(code, dumptree=False): """Produces logical 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 logical lines. """ tree = pytree_utils.ParseCodeToTree(code) 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) if dumptree: pytree_visitor.DumpPyTree(tree, target_stream=sys.stderr) llines = pytree_unwrapper.UnwrapPyTree(tree) for lline in llines: lline.CalculateFormattingInformation() return llines