X-Git-Url: https://git.madduck.net/etc/vim.git/blobdiff_plain/f24635635eef3a998ea02bfcbc663d3dbe129851..31fbd1982f9511c5b7bce93eb133110811f90e0f:/black.py?ds=sidebyside diff --git a/black.py b/black.py index f335ebd..a1a3468 100644 --- a/black.py +++ b/black.py @@ -626,21 +626,22 @@ LOGIC_PRIORITY = 14 STRING_PRIORITY = 12 COMPARATOR_PRIORITY = 10 MATH_PRIORITIES = { - token.VBAR: 8, - token.CIRCUMFLEX: 7, - token.AMPER: 6, - token.LEFTSHIFT: 5, - token.RIGHTSHIFT: 5, - token.PLUS: 4, - token.MINUS: 4, - token.STAR: 3, - token.SLASH: 3, - token.DOUBLESLASH: 3, - token.PERCENT: 3, - token.AT: 3, - token.TILDE: 2, - token.DOUBLESTAR: 1, + token.VBAR: 9, + token.CIRCUMFLEX: 8, + token.AMPER: 7, + token.LEFTSHIFT: 6, + token.RIGHTSHIFT: 6, + token.PLUS: 5, + token.MINUS: 5, + token.STAR: 4, + token.SLASH: 4, + token.DOUBLESLASH: 4, + token.PERCENT: 4, + token.AT: 4, + token.TILDE: 3, + token.DOUBLESTAR: 2, } +DOT_PRIORITY = 1 @dataclass @@ -775,6 +776,7 @@ class Line: comments: List[Tuple[Index, Leaf]] = Factory(list) bracket_tracker: BracketTracker = Factory(BracketTracker) inside_brackets: bool = False + should_explode: bool = False def append(self, leaf: Leaf, preformatted: bool = False) -> None: """Add a new `leaf` to the end of the line. @@ -1314,7 +1316,7 @@ class LineGenerator(Visitor[Line]): The relevant Python language `keywords` for a given statement will be NAME leaves within it. This methods puts those on a separate line. - `parens` holds a set of string leaf values immeditely after which + `parens` holds a set of string leaf values immediately after which invisible parens should be put. """ normalize_invisible_parens(node, parens_after=parens) @@ -1472,7 +1474,9 @@ def whitespace(leaf: Leaf, *, complex_subscript: bool) -> str: # noqa C901 assert p is not None, f"INTERNAL ERROR: hand-made leaf without parent: {leaf!r}" if t == token.COLON and p.type not in { - syms.subscript, syms.subscriptlist, syms.sliceop + syms.subscript, + syms.subscriptlist, + syms.sliceop, }: return NO @@ -1494,7 +1498,10 @@ def whitespace(leaf: Leaf, *, complex_subscript: bool) -> str: # noqa C901 if prevp.type == token.EQUAL: if prevp.parent: if prevp.parent.type in { - syms.arglist, syms.argument, syms.parameters, syms.varargslist + syms.arglist, + syms.argument, + syms.parameters, + syms.varargslist, }: return NO @@ -1648,7 +1655,8 @@ def whitespace(leaf: Leaf, *, complex_subscript: bool) -> str: # noqa C901 prevp_parent = prevp.parent assert prevp_parent is not None if prevp.type == token.COLON and prevp_parent.type in { - syms.subscript, syms.sliceop + syms.subscript, + syms.sliceop, }: return NO @@ -1729,6 +1737,14 @@ def is_split_before_delimiter(leaf: Leaf, previous: Leaf = None) -> int: # Don't treat them as a delimiter. return 0 + if ( + leaf.type == token.DOT + and leaf.parent + and leaf.parent.type not in {syms.import_from, syms.dotted_name} + and (previous is None or previous.type in CLOSING_BRACKETS) + ): + return DOT_PRIORITY + if ( leaf.type in MATH_OPERATORS and leaf.parent @@ -1746,31 +1762,54 @@ def is_split_before_delimiter(leaf: Leaf, previous: Leaf = None) -> int: ): return STRING_PRIORITY + if leaf.type != token.NAME: + return 0 + if ( - leaf.type == token.NAME - and leaf.value == "for" + leaf.value == "for" and leaf.parent and leaf.parent.type in {syms.comp_for, syms.old_comp_for} ): return COMPREHENSION_PRIORITY if ( - leaf.type == token.NAME - and leaf.value == "if" + leaf.value == "if" and leaf.parent and leaf.parent.type in {syms.comp_if, syms.old_comp_if} ): return COMPREHENSION_PRIORITY + if leaf.value in {"if", "else"} and leaf.parent and leaf.parent.type == syms.test: + return TERNARY_PRIORITY + + if leaf.value == "is": + return COMPARATOR_PRIORITY + if ( - leaf.type == token.NAME - and leaf.value in {"if", "else"} + leaf.value == "in" and leaf.parent - and leaf.parent.type == syms.test + and leaf.parent.type in {syms.comp_op, syms.comparison} + and not ( + previous is not None + and previous.type == token.NAME + and previous.value == "not" + ) ): - return TERNARY_PRIORITY + return COMPARATOR_PRIORITY + + if ( + leaf.value == "not" + and leaf.parent + and leaf.parent.type == syms.comp_op + and not ( + previous is not None + and previous.type == token.NAME + and previous.value == "is" + ) + ): + return COMPARATOR_PRIORITY - if leaf.type == token.NAME and leaf.value in LOGIC_OPERATORS and leaf.parent: + if leaf.value in LOGIC_OPERATORS and leaf.parent: return LOGIC_PRIORITY return 0 @@ -1870,15 +1909,15 @@ def split_line( return line_str = str(line).strip("\n") - if is_line_short_enough(line, line_length=line_length, line_str=line_str): + if not line.should_explode and is_line_short_enough( + line, line_length=line_length, line_str=line_str + ): yield line return split_funcs: List[SplitFunc] if line.is_def: split_funcs = [left_hand_split] - elif line.is_import: - split_funcs = [explode_split] else: def rhs(line: Line, py36: bool = False) -> Iterator[Line]: @@ -2041,6 +2080,7 @@ def right_hand_split( ensure_visible(opening_bracket) ensure_visible(closing_bracket) + body.should_explode = should_explode(body, opening_bracket) for result in (head, body, tail): if result: yield result @@ -2105,6 +2145,10 @@ def delimiter_split(line: Line, py36: bool = False) -> Iterator[Line]: except ValueError: raise CannotSplit("No delimiters found") + if delimiter_priority == DOT_PRIORITY: + if bt.delimiter_count_with_priority(delimiter_priority) == 1: + raise CannotSplit("Splitting a single attribute from its owner looks wrong") + current_line = Line(depth=line.depth, inside_brackets=line.inside_brackets) lowest_depth = sys.maxsize trailing_comma_safe = True @@ -2176,26 +2220,6 @@ def standalone_comment_split(line: Line, py36: bool = False) -> Iterator[Line]: yield current_line -def explode_split( - line: Line, py36: bool = False, omit: Collection[LeafID] = () -) -> Iterator[Line]: - """Split by rightmost bracket and immediately split contents by a delimiter.""" - new_lines = list(right_hand_split(line, py36, omit)) - if len(new_lines) != 3: - yield from new_lines - return - - yield new_lines[0] - - try: - yield from delimiter_split(new_lines[1], py36) - - except CannotSplit: - yield new_lines[1] - - yield new_lines[2] - - def is_import(leaf: Leaf) -> bool: """Return True if the given leaf starts an import statement.""" p = leaf.parent @@ -2325,7 +2349,7 @@ def normalize_invisible_parens(node: Node, parens_after: Set[str]) -> None: rpar = Leaf(token.RPAR, ")") index = child.remove() or 0 node.insert_child(index, Node(syms.atom, [lpar, child, rpar])) - else: + elif not (isinstance(child, Leaf) and is_multiline_string(child)): # wrap child in invisible parentheses lpar = Leaf(token.LPAR, "") rpar = Leaf(token.RPAR, "") @@ -2436,6 +2460,12 @@ def is_vararg(leaf: Leaf, within: Set[NodeType]) -> bool: return p.type in within +def is_multiline_string(leaf: Leaf) -> bool: + """Return True if `leaf` is a multiline string that actually spans many lines.""" + value = leaf.value.lstrip("furbFURB") + return value[:3] in {'"""', "'''"} and "\n" in value + + def is_stub_suite(node: Node) -> bool: """Return True if `node` is a suite with a stub body.""" if ( @@ -2505,6 +2535,17 @@ def ensure_visible(leaf: Leaf) -> None: leaf.value = ")" +def should_explode(line: Line, opening_bracket: Leaf) -> bool: + """Should `line` immediately be split with `delimiter_split()` after RHS?""" + return bool( + opening_bracket.parent + and opening_bracket.parent.type in {syms.atom, syms.import_from} + and opening_bracket.value in "[{(" + and line.bracket_tracker.delimiters + and line.bracket_tracker.max_delimiter_priority() == COMMA_PRIORITY + ) + + def is_python36(node: Node) -> bool: """Return True if the current file is using Python 3.6+ features. @@ -2633,7 +2674,15 @@ def get_future_imports(node: Node) -> Set[str]: PYTHON_EXTENSIONS = {".py", ".pyi"} BLACKLISTED_DIRECTORIES = { - "build", "buck-out", "dist", "_build", ".git", ".hg", ".mypy_cache", ".tox", ".venv" + "build", + "buck-out", + "dist", + "_build", + ".git", + ".hg", + ".mypy_cache", + ".tox", + ".venv", }