From d9e71a75ccfefa3d9156a64c03313a0d4ad981e5 Mon Sep 17 00:00:00 2001 From: "Michael J. Sullivan" Date: Wed, 2 Oct 2019 18:57:49 -0700 Subject: [PATCH] Don't break long lines when `type: ignore` is present (#1040) Fixes #997. --- black.py | 33 +++++++++++++++++++++++++++--- tests/data/comments6.py | 4 ++++ tests/data/comments7.py | 42 ++++++++++++++++++++++++++++++++++++++ tests/data/expression.diff | 17 +++++++-------- tests/data/expression.py | 4 +--- 5 files changed, 84 insertions(+), 16 deletions(-) diff --git a/black.py b/black.py index 957e51a..f283ffc 100644 --- a/black.py +++ b/black.py @@ -1325,6 +1325,28 @@ class Line: return False + def contains_unsplittable_type_ignore(self) -> bool: + if not self.leaves: + return False + + # If a 'type: ignore' is attached to the end of a line, we + # can't split the line, because we can't know which of the + # subexpressions the ignore was meant to apply to. + # + # We only want this to apply to actual physical lines from the + # original source, though: we don't want the presence of a + # 'type: ignore' at the end of a multiline expression to + # justify pushing it all onto one line. Thus we + # (unfortunately) need to check the actual source lines and + # only report an unsplittable 'type: ignore' if this line was + # one line in the original code. + if self.leaves[0].lineno == self.leaves[-1].lineno: + for comment in self.comments.get(id(self.leaves[-1]), []): + if is_type_comment(comment, " ignore"): + return True + + return False + def contains_multiline_strings(self) -> bool: for leaf in self.leaves: if is_multiline_string(leaf): @@ -2332,7 +2354,10 @@ def split_line( if ( not line.contains_uncollapsable_type_comments() and not line.should_explode - and is_line_short_enough(line, line_length=line_length, line_str=line_str) + and ( + is_line_short_enough(line, line_length=line_length, line_str=line_str) + or line.contains_unsplittable_type_ignore() + ) ): yield line return @@ -2705,12 +2730,14 @@ def is_import(leaf: Leaf) -> bool: ) -def is_type_comment(leaf: Leaf) -> bool: +def is_type_comment(leaf: Leaf, suffix: str = "") -> bool: """Return True if the given leaf is a special comment. Only returns true for type comments for now.""" t = leaf.type v = leaf.value - return t in {token.COMMENT, t == STANDALONE_COMMENT} and v.startswith("# type:") + return t in {token.COMMENT, t == STANDALONE_COMMENT} and v.startswith( + "# type:" + suffix + ) def normalize_prefix(leaf: Leaf, *, inside_brackets: bool) -> None: diff --git a/tests/data/comments6.py b/tests/data/comments6.py index 6e34b74..7bc83ae 100644 --- a/tests/data/comments6.py +++ b/tests/data/comments6.py @@ -99,5 +99,9 @@ def func( a[-1], # type: ignore ) + c = call( + "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" # type: ignore + ) + result = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa diff --git a/tests/data/comments7.py b/tests/data/comments7.py index f69863e..088dc99 100644 --- a/tests/data/comments7.py +++ b/tests/data/comments7.py @@ -36,6 +36,25 @@ result = ( result = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa + +def func(): + c = call( + 0.0123, + 0.0456, + 0.0789, + 0.0123, + 0.0789, + a[-1], # type: ignore + ) + + # The type: ignore exception only applies to line length, not + # other types of formatting. + c = call( + "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", # type: ignore + "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa", "aaaaaaaa" + ) + + # output from .config import ( @@ -71,3 +90,26 @@ result = 1 # look ma, no comment migration xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx result = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa result = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # aaa + + +def func(): + c = call( + 0.0123, 0.0456, 0.0789, 0.0123, 0.0789, a[-1] # type: ignore + ) + + # The type: ignore exception only applies to line length, not + # other types of formatting. + c = call( + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", # type: ignore + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + "aaaaaaaa", + ) diff --git a/tests/data/expression.diff b/tests/data/expression.diff index c3ee14d..eff98f9 100644 --- a/tests/data/expression.diff +++ b/tests/data/expression.diff @@ -118,7 +118,7 @@ call(**self.screen_kwargs) call(b, **self.screen_kwargs) lukasz.langa.pl -@@ -94,23 +115,25 @@ +@@ -94,23 +115,23 @@ 1.0 .real ....__class__ list[str] @@ -132,15 +132,12 @@ xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__) ) --xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore -- sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__) --) - xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[ - ..., List[SomeClass] + xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore + sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__) + ) +-xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[ +- ..., List[SomeClass] -] = classmethod(sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__)) # type: ignore -+] = classmethod( # type: ignore -+ sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__) -+) +xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( + sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__) +) # type: ignore @@ -149,7 +146,7 @@ slice[0:1:2] slice[:] slice[:-1] -@@ -134,113 +157,171 @@ +@@ -134,113 +155,171 @@ numpy[-(c + 1) :, d] numpy[:, l[-2]] numpy[:, ::-1] diff --git a/tests/data/expression.py b/tests/data/expression.py index 912f76d..3851249 100644 --- a/tests/data/expression.py +++ b/tests/data/expression.py @@ -374,9 +374,7 @@ very_long_variable_name_filters: t.List[ xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__) ) -xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[ - ..., List[SomeClass] -] = classmethod( # type: ignore +xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( # type: ignore sync(async_xxxx_xxx_xxxx_xxxxx_xxxx_xxx.__func__) ) xxxx_xxx_xxxx_xxxxx_xxxx_xxx: Callable[..., List[SomeClass]] = classmethod( -- 2.39.5