- `Black` now respects `--skip-string-normalization` when normalizing multiline
docstring quotes (#1637)
+- `Black` no longer removes all empty lines between non-function code and decorators
+ when formatting typing stubs. Now `Black` enforces a single empty line. (#1646)
+
- `Black` no longer adds an incorrect space after a parenthesized assignment expression
in if/while statements (#1655)
- `Black` now respects `--skip-string-normalization` when normalizing multiline
docstring quotes (#1637)
+- `Black` no longer removes all empty lines between non-function code and decorators
+ when formatting typing stubs. Now `Black` enforces a single empty line. (#1646)
+
- `Black` no longer adds an incorrect space after a parenthesized assignment expression
in if/while statements (#1655)
return 0, 0
if self.previous_line.is_decorator:
+ if self.is_pyi and current_line.is_stub_class:
+ # Insert an empty line after a decorated stub class
+ return 0, 1
+
return 0, 0
if self.previous_line.depth < current_line.depth and (
newlines = 0
else:
newlines = 1
- elif current_line.is_def and not self.previous_line.is_def:
- # Blank line between a block of functions and a block of non-functions
+ elif (
+ current_line.is_def or current_line.is_decorator
+ ) and not self.previous_line.is_def:
+ # Blank line between a block of functions (maybe with preceding
+ # decorators) and a block of non-functions
newlines = 1
else:
newlines = 0
-def f(): ...
+from typing import Union
+
+@bird
+def zoo(): ...
+
+class A: ...
+@bar
+class B:
+ def BMethod(self) -> None: ...
+ @overload
+ def BMethod(self, arg : List[str]) -> None: ...
+
+class C: ...
+@hmm
+class D: ...
+class E: ...
+
+@baz
+def foo() -> None:
+ ...
+
+class F (A , C): ...
+def spam() -> None: ...
+
+@overload
+def spam(arg: str) -> str: ...
+
+var : int = 1
+
+def eggs() -> Union[str, int]: ...
-def g(): ...
# output
-def f(): ...
-def g(): ...
+
+from typing import Union
+
+@bird
+def zoo(): ...
+
+class A: ...
+
+@bar
+class B:
+ def BMethod(self) -> None: ...
+ @overload
+ def BMethod(self, arg: List[str]) -> None: ...
+
+class C: ...
+
+@hmm
+class D: ...
+
+class E: ...
+
+@baz
+def foo() -> None: ...
+
+class F(A, C): ...
+
+def spam() -> None: ...
+@overload
+def spam(arg: str) -> str: ...
+
+var: int = 1
+
+def eggs() -> Union[str, int]: ...
black.assert_stable(source, actual, DEFAULT_MODE)
def test_single_file_force_pyi(self) -> None:
- reg_mode = DEFAULT_MODE
pyi_mode = replace(DEFAULT_MODE, is_pyi=True)
contents, expected = read_data("force_pyi")
with cache_dir() as workspace:
# verify cache with --pyi is separate
pyi_cache = black.read_cache(pyi_mode)
self.assertIn(path, pyi_cache)
- normal_cache = black.read_cache(reg_mode)
+ normal_cache = black.read_cache(DEFAULT_MODE)
self.assertNotIn(path, normal_cache)
- self.assertEqual(actual, expected)
+ self.assertFormatEqual(expected, actual)
+ black.assert_equivalent(contents, actual)
+ black.assert_stable(contents, actual, pyi_mode)
@event_loop()
def test_multi_file_force_pyi(self) -> None: