2
2
Generating lines of code.
3
3
"""
4
4
import sys
5
+ from dataclasses import dataclass
5
6
from enum import Enum , auto
6
7
from functools import partial , wraps
7
8
from typing import Collection , Iterator , List , Optional , Set , Union , cast
24
25
from black .mode import Feature , Mode , Preview
25
26
from black .nodes import (
26
27
ASSIGNMENTS ,
28
+ BRACKETS ,
27
29
CLOSING_BRACKETS ,
28
30
OPENING_BRACKETS ,
29
31
RARROW ,
@@ -634,6 +636,17 @@ def left_hand_split(line: Line, _features: Collection[Feature] = ()) -> Iterator
634
636
yield result
635
637
636
638
639
+ @dataclass
640
+ class _RHSResult :
641
+ """Intermediate split result from a right hand split."""
642
+
643
+ head : Line
644
+ body : Line
645
+ tail : Line
646
+ opening_bracket : Leaf
647
+ closing_bracket : Leaf
648
+
649
+
637
650
def right_hand_split (
638
651
line : Line ,
639
652
line_length : int ,
@@ -648,6 +661,22 @@ def right_hand_split(
648
661
649
662
Note: running this function modifies `bracket_depth` on the leaves of `line`.
650
663
"""
664
+ rhs_result = _first_right_hand_split (line , omit = omit )
665
+ yield from _maybe_split_omitting_optional_parens (
666
+ rhs_result , line , line_length , features = features , omit = omit
667
+ )
668
+
669
+
670
+ def _first_right_hand_split (
671
+ line : Line ,
672
+ omit : Collection [LeafID ] = (),
673
+ ) -> _RHSResult :
674
+ """Split the line into head, body, tail starting with the last bracket pair.
675
+
676
+ Note: this function should not have side effects. It's relied upon by
677
+ _maybe_split_omitting_optional_parens to get an opinion whether to prefer
678
+ splitting on the right side of an assignment statement.
679
+ """
651
680
tail_leaves : List [Leaf ] = []
652
681
body_leaves : List [Leaf ] = []
653
682
head_leaves : List [Leaf ] = []
@@ -683,51 +712,114 @@ def right_hand_split(
683
712
tail_leaves , line , opening_bracket , component = _BracketSplitComponent .tail
684
713
)
685
714
bracket_split_succeeded_or_raise (head , body , tail )
715
+ return _RHSResult (head , body , tail , opening_bracket , closing_bracket )
716
+
717
+
718
+ def _maybe_split_omitting_optional_parens (
719
+ rhs : _RHSResult ,
720
+ line : Line ,
721
+ line_length : int ,
722
+ features : Collection [Feature ] = (),
723
+ omit : Collection [LeafID ] = (),
724
+ ) -> Iterator [Line ]:
686
725
if (
687
726
Feature .FORCE_OPTIONAL_PARENTHESES not in features
688
727
# the opening bracket is an optional paren
689
- and opening_bracket .type == token .LPAR
690
- and not opening_bracket .value
728
+ and rhs . opening_bracket .type == token .LPAR
729
+ and not rhs . opening_bracket .value
691
730
# the closing bracket is an optional paren
692
- and closing_bracket .type == token .RPAR
693
- and not closing_bracket .value
731
+ and rhs . closing_bracket .type == token .RPAR
732
+ and not rhs . closing_bracket .value
694
733
# it's not an import (optional parens are the only thing we can split on
695
734
# in this case; attempting a split without them is a waste of time)
696
735
and not line .is_import
697
736
# there are no standalone comments in the body
698
- and not body .contains_standalone_comments (0 )
737
+ and not rhs . body .contains_standalone_comments (0 )
699
738
# and we can actually remove the parens
700
- and can_omit_invisible_parens (body , line_length )
739
+ and can_omit_invisible_parens (rhs . body , line_length )
701
740
):
702
- omit = {id (closing_bracket ), * omit }
741
+ omit = {id (rhs . closing_bracket ), * omit }
703
742
try :
704
- yield from right_hand_split (line , line_length , features = features , omit = omit )
705
- return
743
+ # The _RHSResult Omitting Optional Parens.
744
+ rhs_oop = _first_right_hand_split (line , omit = omit )
745
+ if not (
746
+ Preview .prefer_splitting_right_hand_side_of_assignments in line .mode
747
+ # the split is right after `=`
748
+ and len (rhs .head .leaves ) >= 2
749
+ and rhs .head .leaves [- 2 ].type == token .EQUAL
750
+ # the left side of assignement contains brackets
751
+ and any (leaf .type in BRACKETS for leaf in rhs .head .leaves [:- 1 ])
752
+ # the left side of assignment is short enough (the -1 is for the ending
753
+ # optional paren)
754
+ and is_line_short_enough (rhs .head , line_length = line_length - 1 )
755
+ # the left side of assignment won't explode further because of magic
756
+ # trailing comma
757
+ and rhs .head .magic_trailing_comma is None
758
+ # the split by omitting optional parens isn't preferred by some other
759
+ # reason
760
+ and not _prefer_split_rhs_oop (rhs_oop , line_length = line_length )
761
+ ):
762
+ yield from _maybe_split_omitting_optional_parens (
763
+ rhs_oop , line , line_length , features = features , omit = omit
764
+ )
765
+ return
706
766
707
767
except CannotSplit as e :
708
768
if not (
709
- can_be_split (body )
710
- or is_line_short_enough (body , line_length = line_length )
769
+ can_be_split (rhs . body )
770
+ or is_line_short_enough (rhs . body , line_length = line_length )
711
771
):
712
772
raise CannotSplit (
713
773
"Splitting failed, body is still too long and can't be split."
714
774
) from e
715
775
716
- elif head .contains_multiline_strings () or tail .contains_multiline_strings ():
776
+ elif (
777
+ rhs .head .contains_multiline_strings ()
778
+ or rhs .tail .contains_multiline_strings ()
779
+ ):
717
780
raise CannotSplit (
718
781
"The current optional pair of parentheses is bound to fail to"
719
782
" satisfy the splitting algorithm because the head or the tail"
720
783
" contains multiline strings which by definition never fit one"
721
784
" line."
722
785
) from e
723
786
724
- ensure_visible (opening_bracket )
725
- ensure_visible (closing_bracket )
726
- for result in (head , body , tail ):
787
+ ensure_visible (rhs . opening_bracket )
788
+ ensure_visible (rhs . closing_bracket )
789
+ for result in (rhs . head , rhs . body , rhs . tail ):
727
790
if result :
728
791
yield result
729
792
730
793
794
+ def _prefer_split_rhs_oop (rhs_oop : _RHSResult , line_length : int ) -> bool :
795
+ """
796
+ Returns whether we should prefer the result from a split omitting optional parens.
797
+ """
798
+ has_closing_bracket_after_assign = False
799
+ for leaf in reversed (rhs_oop .head .leaves ):
800
+ if leaf .type == token .EQUAL :
801
+ break
802
+ if leaf .type in CLOSING_BRACKETS :
803
+ has_closing_bracket_after_assign = True
804
+ break
805
+ return (
806
+ # contains matching brackets after the `=` (done by checking there is a
807
+ # closing bracket)
808
+ has_closing_bracket_after_assign
809
+ or (
810
+ # the split is actually from inside the optional parens (done by checking
811
+ # the first line still contains the `=`)
812
+ any (leaf .type == token .EQUAL for leaf in rhs_oop .head .leaves )
813
+ # the first line is short enough
814
+ and is_line_short_enough (rhs_oop .head , line_length = line_length )
815
+ )
816
+ # contains unsplittable type ignore
817
+ or rhs_oop .head .contains_unsplittable_type_ignore ()
818
+ or rhs_oop .body .contains_unsplittable_type_ignore ()
819
+ or rhs_oop .tail .contains_unsplittable_type_ignore ()
820
+ )
821
+
822
+
731
823
def bracket_split_succeeded_or_raise (head : Line , body : Line , tail : Line ) -> None :
732
824
"""Raise :exc:`CannotSplit` if the last left- or right-hand split failed.
733
825
0 commit comments