Check stability for both preview and non-preview styles (#3423)
And fix parens-related test failures this found. Co-authored-by: Richard Si <63936253+ichard26@users.noreply.github.com>
This commit is contained in:
parent
c0089ef19d
commit
159984a735
@ -17,6 +17,8 @@
|
|||||||
<!-- Changes that affect Black's preview style -->
|
<!-- Changes that affect Black's preview style -->
|
||||||
|
|
||||||
- Fix a crash in preview style with assert + parenthesized string (#3415)
|
- Fix a crash in preview style with assert + parenthesized string (#3415)
|
||||||
|
- Fix crashes in preview style with walrus operators used in function return annotations
|
||||||
|
and except clauses (#3423)
|
||||||
- Do not put the closing quotes in a docstring on a separate line, even if the line is
|
- Do not put the closing quotes in a docstring on a separate line, even if the line is
|
||||||
too long (#3430)
|
too long (#3430)
|
||||||
- Long values in dict literals are now wrapped in parentheses; correspondingly
|
- Long values in dict literals are now wrapped in parentheses; correspondingly
|
||||||
|
@ -1268,6 +1268,8 @@ def maybe_make_parens_invisible_in_atom(
|
|||||||
syms.expr_stmt,
|
syms.expr_stmt,
|
||||||
syms.assert_stmt,
|
syms.assert_stmt,
|
||||||
syms.return_stmt,
|
syms.return_stmt,
|
||||||
|
syms.except_clause,
|
||||||
|
syms.funcdef,
|
||||||
# these ones aren't useful to end users, but they do please fuzzers
|
# these ones aren't useful to end users, but they do please fuzzers
|
||||||
syms.for_stmt,
|
syms.for_stmt,
|
||||||
syms.del_stmt,
|
syms.del_stmt,
|
||||||
|
@ -114,6 +114,6 @@ def func(match: case, case: match) -> case:
|
|||||||
|
|
||||||
match bar1:
|
match bar1:
|
||||||
case Foo(
|
case Foo(
|
||||||
normal=x, perhaps=[list, {an: d, dict: 1.0}] as y, otherwise=something, q=t as u
|
normal=x, perhaps=[list, {"x": d, "y": 1.0}] as y, otherwise=something, q=t as u
|
||||||
):
|
):
|
||||||
pass
|
pass
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
from dataclasses import replace
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Iterator, List, Optional, Tuple
|
from typing import Any, Iterator, List, Optional, Tuple
|
||||||
@ -56,6 +57,10 @@ def _assert_format_equal(expected: str, actual: str) -> None:
|
|||||||
assert actual == expected
|
assert actual == expected
|
||||||
|
|
||||||
|
|
||||||
|
class FormatFailure(Exception):
|
||||||
|
"""Used to wrap failures when assert_format() runs in an extra mode."""
|
||||||
|
|
||||||
|
|
||||||
def assert_format(
|
def assert_format(
|
||||||
source: str,
|
source: str,
|
||||||
expected: str,
|
expected: str,
|
||||||
@ -70,12 +75,57 @@ def assert_format(
|
|||||||
safety guards so they don't just crash with a SyntaxError. Please note this is
|
safety guards so they don't just crash with a SyntaxError. Please note this is
|
||||||
separate from TargetVerson Mode configuration.
|
separate from TargetVerson Mode configuration.
|
||||||
"""
|
"""
|
||||||
|
_assert_format_inner(
|
||||||
|
source, expected, mode, fast=fast, minimum_version=minimum_version
|
||||||
|
)
|
||||||
|
|
||||||
|
# For both preview and non-preview tests, ensure that Black doesn't crash on
|
||||||
|
# this code, but don't pass "expected" because the precise output may differ.
|
||||||
|
try:
|
||||||
|
_assert_format_inner(
|
||||||
|
source,
|
||||||
|
None,
|
||||||
|
replace(mode, preview=not mode.preview),
|
||||||
|
fast=fast,
|
||||||
|
minimum_version=minimum_version,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
text = "non-preview" if mode.preview else "preview"
|
||||||
|
raise FormatFailure(
|
||||||
|
f"Black crashed formatting this case in {text} mode."
|
||||||
|
) from e
|
||||||
|
# Similarly, setting line length to 1 is a good way to catch
|
||||||
|
# stability bugs. But only in non-preview mode because preview mode
|
||||||
|
# currently has a lot of line length 1 bugs.
|
||||||
|
try:
|
||||||
|
_assert_format_inner(
|
||||||
|
source,
|
||||||
|
None,
|
||||||
|
replace(mode, preview=False, line_length=1),
|
||||||
|
fast=fast,
|
||||||
|
minimum_version=minimum_version,
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
raise FormatFailure(
|
||||||
|
"Black crashed formatting this case with line-length set to 1."
|
||||||
|
) from e
|
||||||
|
|
||||||
|
|
||||||
|
def _assert_format_inner(
|
||||||
|
source: str,
|
||||||
|
expected: Optional[str] = None,
|
||||||
|
mode: black.Mode = DEFAULT_MODE,
|
||||||
|
*,
|
||||||
|
fast: bool = False,
|
||||||
|
minimum_version: Optional[Tuple[int, int]] = None,
|
||||||
|
) -> None:
|
||||||
actual = black.format_str(source, mode=mode)
|
actual = black.format_str(source, mode=mode)
|
||||||
|
if expected is not None:
|
||||||
_assert_format_equal(expected, actual)
|
_assert_format_equal(expected, actual)
|
||||||
# It's not useful to run safety checks if we're expecting no changes anyway. The
|
# It's not useful to run safety checks if we're expecting no changes anyway. The
|
||||||
# assertion right above will raise if reality does actually make changes. This just
|
# assertion right above will raise if reality does actually make changes. This just
|
||||||
# avoids wasted CPU cycles.
|
# avoids wasted CPU cycles.
|
||||||
if not fast and source != expected:
|
if not fast and source != actual:
|
||||||
# Unfortunately the AST equivalence check relies on the built-in ast module
|
# Unfortunately the AST equivalence check relies on the built-in ast module
|
||||||
# being able to parse the code being formatted. This doesn't always work out
|
# being able to parse the code being formatted. This doesn't always work out
|
||||||
# when checking modern code on older versions.
|
# when checking modern code on older versions.
|
||||||
|
Loading…
Reference in New Issue
Block a user