Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stability fixup: address stability issues relating to interaction between magic commas and invisible parentheses #1958

Closed
wants to merge 114 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
114 commits
Select commit Hold shift + click to select a range
fa0b64d
Add illustrative test data
jayaddison Feb 3, 2021
21842f2
Fixup: handling of invisible parentheses for assert and return statem…
jayaddison Feb 3, 2021
fdff084
Re-enable test_trailing_comma_optional_parens_stability3 since it has…
jayaddison Feb 3, 2021
0bb718c
Use a 'pass' statement since 'maybe_make_parens_invisible_in_atom' cu…
jayaddison Feb 3, 2021
82ab09d
Do not omit any tokens when selecting the last two leaves
jayaddison Feb 3, 2021
f154042
Cleanup: remove slightly arbitrary 'pass' handling for assert and ret…
jayaddison Feb 3, 2021
d262d29
Update output expectation for trailing comma reformatting test case
jayaddison Feb 3, 2021
23facce
Cleanup: remove redundant code path
jayaddison Feb 3, 2021
543fc7e
Update primer.json to permit formatting changes to be passed by conti…
jayaddison Feb 3, 2021
27e1f05
Merge branch 'master' into stability/invisible-parens-assert-return
jayaddison Feb 4, 2021
6c6d262
Temporarily revert src directory changes
jayaddison Feb 4, 2021
2152848
Add additional test cases from psf/black#1629
jayaddison Feb 4, 2021
a23e87d
Revert "Temporarily revert src directory changes"
jayaddison Feb 4, 2021
065abbf
Revert "Update primer.json to permit formatting changes to be passed …
jayaddison Feb 4, 2021
10015f6
Revert "Cleanup: remove redundant code path"
jayaddison Feb 4, 2021
16bf728
Revert "Update output expectation for trailing comma reformatting tes…
jayaddison Feb 4, 2021
f4ee9dc
Revert "Cleanup: remove slightly arbitrary 'pass' handling for assert…
jayaddison Feb 4, 2021
4c2947f
Revert "Do not omit any tokens when selecting the last two leaves"
jayaddison Feb 4, 2021
461a828
Revert "Use a 'pass' statement since 'maybe_make_parens_invisible_in_…
jayaddison Feb 4, 2021
07f5796
Revert "Re-enable test_trailing_comma_optional_parens_stability3 sinc…
jayaddison Feb 4, 2021
39caefb
Revert "Fixup: handling of invisible parentheses for assert and retur…
jayaddison Feb 4, 2021
7c1482d
Remove example code that raises a Python TypeError during evaluation
jayaddison Feb 4, 2021
ab07b03
Indicate that failures are expected in the 'test_invisible_parens_ins…
jayaddison Feb 4, 2021
1109e33
Brevity: rename method
jayaddison Feb 4, 2021
f6eab7c
Clarity: isolate and extract each responsibility from an overloaded v…
jayaddison Feb 4, 2021
d4a2e36
Brevity: only use the variables required to convey the intended expre…
jayaddison Feb 4, 2021
ebbd3e8
Consistency: use variable names that correspond to the methods they i…
jayaddison Feb 4, 2021
d806503
Clarity: special case: avoid using variables that have the same names…
jayaddison Feb 4, 2021
7dba4ba
Simplification: only use special-case token retrieval logic when magi…
jayaddison Feb 4, 2021
27a2dfe
Simplification: only yield empty omit list when magic trailing comma …
jayaddison Feb 4, 2021
3a45017
Cleanup: remove unused / redundant variables from conditionals
jayaddison Feb 4, 2021
4ff708f
Merge branch 'refactor/distinguished-variable-responsibilities' into …
jayaddison Feb 4, 2021
95677ff
Merge branch 'master' into stability/invisible-parens-assert-return
jayaddison Feb 5, 2021
e9a7326
Revert "Address pre-existing trailing commas when not in the rightmos…
jayaddison Feb 5, 2021
8b997a8
Unset failure expectations on a few test cases
jayaddison Feb 5, 2021
ec1b0ab
Work-in-progress: investigate bracket matching
jayaddison Feb 5, 2021
b90268e
Revert "Work-in-progress: investigate bracket matching"
jayaddison Feb 5, 2021
268e3f3
Fixup: handling of invisible parentheses for assert and return statem…
jayaddison Feb 3, 2021
0596b38
Use a 'pass' statement since 'maybe_make_parens_invisible_in_atom' cu…
jayaddison Feb 3, 2021
58c3cce
Expectation adjustment: remove parentheses around pre-f-string format…
jayaddison Feb 5, 2021
235b854
Restore latest function_trailing_comma tests
jayaddison Feb 6, 2021
e245b1a
Add additional test coverage
jayaddison Feb 7, 2021
acffae3
When a magic comma is present in the line, delay emission of empty tr…
jayaddison Feb 7, 2021
d036da4
Add additional test coverage
jayaddison Feb 7, 2021
7da423e
Add special-case handling of 'if' statements within normalize_invisib…
jayaddison Feb 7, 2021
634b1a3
When a magic comma is present in the line, emit an empty trailer when…
jayaddison Feb 7, 2021
e8ad631
black-primer configuration: indicate that sqlalchemy would require fo…
jayaddison Feb 7, 2021
48ac43f
Include removal of work-in-progress test from 586d24236e6b57bc3b5da85…
jayaddison Feb 7, 2021
62b76ca
Revert "Add additional test cases from psf/black#1629"
jayaddison Feb 7, 2021
9ff5f98
black-primer configuration: indicate that flake8-bugbear would requir…
jayaddison Feb 7, 2021
176a96a
Re-apply test re-organization cleanup of 'function2' test from e6cd10…
jayaddison Feb 7, 2021
b93b955
Apply test organization patterns from e6cd10e7615f4df537e2eaefcf3904a…
jayaddison Feb 7, 2021
e96a683
Nitpick: rename the test; it should be considered a test of stability…
jayaddison Feb 7, 2021
6763046
Include line comment copy behaviour fixup from 586d24236e6b57bc3b5da8…
jayaddison Feb 7, 2021
0aa8083
Cleanup: yield existing 'omit' variable rather than literal empty sets
jayaddison Feb 8, 2021
efc7552
Readability: reduce boolean nesting
jayaddison Feb 9, 2021
0666fc1
Merge branch 'refactor/distinguished-variable-responsibilities' into …
jayaddison Feb 9, 2021
b2a4a29
Include explanatory comments in 'rhs' method from 586d24236e6b57bc3b5…
jayaddison Feb 9, 2021
934c79d
Include short-circuit condition in 'is_one_tuple_between' method from…
jayaddison Feb 9, 2021
c16e29a
Include extracted '_can_omit_opening_paren', '_can_omit_closing_paren…
jayaddison Feb 9, 2021
7dfb59a
Relocate 'last', 'penultimate' variable declarations nearer to first use
jayaddison Feb 9, 2021
a62b47a
Merge branch 'master' into refactor/distinguished-variable-responsibi…
jayaddison Feb 9, 2021
6423a8d
Relocate comment to minimize review diff size
jayaddison Feb 9, 2021
82ca108
Merge branch 'refactor/distinguished-variable-responsibilities' into …
jayaddison Feb 9, 2021
8343663
Remove empty line
jayaddison Feb 9, 2021
66ef77a
Cleanup: undo accidental changes to remainder logic in '_can_omit_ope…
jayaddison Feb 9, 2021
4126cdd
Restore redundant condition in order to further minimize review diff …
jayaddison Feb 9, 2021
34cce10
Restore empty line
jayaddison Feb 9, 2021
8fcfcbf
Restore explicit return value
jayaddison Feb 9, 2021
0adad3a
Include extraction of 'prev' variable within 'generate_trailers_to_om…
jayaddison Feb 9, 2021
788002a
Restore empty line
jayaddison Feb 9, 2021
879cbe2
Remove empty line
jayaddison Feb 9, 2021
c7d7f59
Restore accurate comment
jayaddison Feb 9, 2021
9f0289a
Minimize changes: more closely resemble original conditional logic
jayaddison Feb 10, 2021
4d39520
Merge branch 'refactor/distinguished-variable-responsibilities' into …
jayaddison Feb 10, 2021
b4c9238
Update test expectations
jayaddison Feb 10, 2021
6bb74e0
Cleanup: remove redundant 'yield' statement
jayaddison Feb 10, 2021
695ecf1
Cleanup: remove redundant magic comma value unassignment
jayaddison Feb 10, 2021
cb4ce1b
Cleanup: remove redundant conditional check
jayaddison Feb 10, 2021
7f3375f
black-primer configuration: indicate that tox would require formattin…
jayaddison Feb 10, 2021
a8df515
Cleanup: remove redundant 'return_stmt' value test
jayaddison Feb 10, 2021
ae519ca
Isolate logically separate conditional paths
jayaddison Feb 10, 2021
630771a
Reduce visits to 'inner_brackets' conditional path
jayaddison Feb 10, 2021
169ef38
Add explanatory and placeholder comments
jayaddison Feb 10, 2021
c74a1c5
Merge branch 'master' into refactor/distinguished-variable-responsibi…
jayaddison Feb 10, 2021
15788c5
Merge branch 'master' into stability/invisible-parens-assert-return
jayaddison Feb 10, 2021
3f8673d
Consistency: use a set to hold symbol types during membership test
jayaddison Feb 10, 2021
4d5ba05
Include 'BracketMatchError' exception handler and comment from 586d24…
jayaddison Feb 10, 2021
8c19ff5
Revert incorrect test expectation updates
jayaddison Feb 11, 2021
7c4a6a0
Merge branch 'master' into refactor/distinguished-variable-responsibi…
jayaddison Feb 12, 2021
1096bc9
Remove special-case invisible parentheses logic related to magic comm…
jayaddison Feb 12, 2021
e04ed95
Merge branch 'cleanup/remove-special-case-invisible-parens-handling' …
jayaddison Feb 13, 2021
16d2505
Include removal of line_length=1 from 586d24236e6b57bc3b5da85fdbe2563…
jayaddison Feb 13, 2021
fe64f19
Update test expectations (note: this includes output that exceeds the…
jayaddison Feb 13, 2021
b061589
Remove special-case handling for 'assert' and 'if' statements
jayaddison Feb 13, 2021
60d5191
Restore last_two_except logic from 586d24236e6b57bc3b5da85fdbe2563835…
jayaddison Feb 13, 2021
6b10579
Also allow omission of invisible parentheses for math operators
jayaddison Feb 13, 2021
eab9b2b
Remove outdated comment in test data
jayaddison Feb 13, 2021
c2bf24b
black-primer configuration: indicate that tox would not require forma…
jayaddison Feb 13, 2021
0956060
black-primer configuration: indicate that bandersnatch would require …
jayaddison Feb 13, 2021
ae45ee3
Merge branch 'master' into stability/invisible-parens-assert-return
jayaddison Feb 16, 2021
b0aaff0
Cleanup: remove 'test_function' test case; formatting of the 'functio…
jayaddison Feb 17, 2021
10d56e5
Cleanup: restore doubling of the 'stack' variable from 586d24236e6b57…
jayaddison Feb 17, 2021
3dabcc3
Merge branch 'master' into stability/invisible-parens-assert-return
jayaddison Feb 20, 2021
17e9540
Cleanup: remove unused test module
jayaddison Feb 21, 2021
5386773
Undo method signature changes to 'can_omit_invisible_parens' since it…
jayaddison Feb 21, 2021
f7bec57
Cleanup: undo change to use implicit argument name
jayaddison Feb 21, 2021
5a2111a
Merge branch 'master' into stability/invisible-parens-assert-return
jayaddison Feb 22, 2021
3cc7102
Add changelog entry
jayaddison Feb 22, 2021
d868154
Merge branch 'master' into stability/invisible-parens-assert-return
jayaddison Feb 27, 2021
47fc731
Merge branch 'master' into stability/invisible-parens-assert-return
jayaddison Feb 28, 2021
372b74c
Merge branch 'master' into stability/invisible-parens-assert-return
jayaddison Mar 3, 2021
b48e35c
Fixup for incorrect changelog merge conflict resolution
jayaddison Mar 3, 2021
bab0899
Merge branch 'master' into stability/invisible-parens-assert-return
ambv Apr 1, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Expand Up @@ -38,6 +38,8 @@
- Added `--stdin-filename` argument to allow stdin to respect `--force-exclude` rules
(#1780)

- Reduce second-pass formatting stability errors (#1629)

- Lines ending with `fmt: skip` will now be not formatted (#1800)

- PR #2053: Black no longer relies on typed-ast for Python 3.8 and higher
Expand Down
106 changes: 26 additions & 80 deletions src/black/__init__.py
Expand Up @@ -216,7 +216,6 @@ class Feature(Enum):
ASSIGNMENT_EXPRESSIONS = 8
POS_ONLY_ARGUMENTS = 9
RELAXED_DECORATORS = 10
FORCE_OPTIONAL_PARENTHESES = 50


VERSION_TO_FEATURES: Dict[TargetVersion, Set[Feature]] = {
Expand Down Expand Up @@ -1359,7 +1358,6 @@ class BracketTracker:
previous: Optional[Leaf] = None
_for_loop_depths: List[int] = field(default_factory=list)
_lambda_argument_depths: List[int] = field(default_factory=list)
invisible: List[Leaf] = field(default_factory=list)

def mark(self, leaf: Leaf) -> None:
"""Mark `leaf` with bracket-related metadata. Keep track of delimiters.
Expand Down Expand Up @@ -1391,8 +1389,6 @@ def mark(self, leaf: Leaf) -> None:
f" bracket: {leaf}"
) from e
leaf.opening_bracket = opening_bracket
if not leaf.value:
self.invisible.append(leaf)
leaf.bracket_depth = self.depth
if self.depth == 0:
delim = is_split_before_delimiter(leaf, self.previous)
Expand All @@ -1405,8 +1401,6 @@ def mark(self, leaf: Leaf) -> None:
if leaf.type in OPENING_BRACKETS:
self.bracket_match[self.depth, BRACKET[leaf.type]] = leaf
self.depth += 1
if not leaf.value:
self.invisible.append(leaf)
self.previous = leaf
self.maybe_increment_lambda_arguments(leaf)
self.maybe_increment_for_loop_variable(leaf)
Expand Down Expand Up @@ -2810,8 +2804,17 @@ def rhs(line: Line, features: Collection[Feature]) -> Iterator[Line]:
# We are accumulating lines in `result` because we might want to abort
# mission and return the original line in the end, or attempt a different
# split altogether.
result: List[Line] = []
try:
result = run_transformer(line, transform, mode, features, line_str=line_str)
for transformed_line in transform(line, features):
if str(transformed_line).strip("\n") == line_str:
raise CannotTransform(
"Line transformer returned an unchanged result"
)

result.extend(
transform_line(transformed_line, mode=mode, features=features)
)
except CannotTransform:
continue
else:
Expand Down Expand Up @@ -2852,7 +2855,6 @@ class StringTransformer(ABC):

line_length: int
normalize_strings: bool
__name__ = "StringTransformer"

@abstractmethod
def do_match(self, line: Line) -> TMatchResult:
Expand Down Expand Up @@ -4199,9 +4201,10 @@ def _return_match(LL: List[Leaf]) -> Optional[int]:
"""
# If this line is apart of a return/yield statement and the first leaf
# contains either the "return" or "yield" keywords...
if parent_type(LL[0]) in [syms.return_stmt, syms.yield_expr] and LL[
0
].value in ["return", "yield"]:
if (
parent_type(LL[0]) in [syms.return_stmt, syms.yield_expr]
and LL[0].value in ["return", "yield"]
):
is_valid_index = is_valid_index_factory(LL)

idx = 2 if is_valid_index(1) and is_empty_par(LL[1]) else 1
Expand Down Expand Up @@ -4926,9 +4929,8 @@ def right_hand_split(
tail = bracket_split_build_line(tail_leaves, line, opening_bracket)
bracket_split_succeeded_or_raise(head, body, tail)
if (
Feature.FORCE_OPTIONAL_PARENTHESES not in features
# the opening bracket is an optional paren
and opening_bracket.type == token.LPAR
opening_bracket.type == token.LPAR
and not opening_bracket.value
# the closing bracket is an optional paren
and closing_bracket.type == token.RPAR
Expand Down Expand Up @@ -6008,18 +6010,6 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf
if leaf is opening_bracket:
opening_bracket = None
elif leaf.type in CLOSING_BRACKETS:
prev = line.leaves[index - 1] if index > 0 else None
if (
prev
and prev.type == token.COMMA
and not is_one_tuple_between(
leaf.opening_bracket, leaf, line.leaves
)
):
# Never omit bracket pairs with trailing commas.
# We need to explode on those.
break

inner_brackets.add(id(leaf))
elif leaf.type in CLOSING_BRACKETS:
prev = line.leaves[index - 1] if index > 0 else None
Expand All @@ -6031,20 +6021,17 @@ def generate_trailers_to_omit(line: Line, line_length: int) -> Iterator[Set[Leaf
continue

if closing_bracket:
# Omit tokens to the right of brackets that contain a trailing comma
if closing_bracket is line.magic_trailing_comma:
yield omit
# TODO: Understand and explain this line; are there edge cases here?
if line.magic_trailing_comma and inner_brackets:
yield omit
omit.add(id(closing_bracket))
omit.update(inner_brackets)
inner_brackets.clear()
yield omit

if (
prev
and prev.type == token.COMMA
and not is_one_tuple_between(leaf.opening_bracket, leaf, line.leaves)
):
# Never omit bracket pairs with trailing commas.
# We need to explode on those.
break

if leaf.value:
opening_bracket = leaf.opening_bracket
closing_bracket = leaf
Expand Down Expand Up @@ -6696,13 +6683,17 @@ def can_omit_invisible_parens(

penultimate = line.leaves[-2]
last = line.leaves[-1]
if line.magic_trailing_comma:
if omit_on_explode:
try:
penultimate, last = last_two_except(line.leaves, omit=omit_on_explode)
except LookupError:
# Turns out we'd omit everything. We cannot skip the optional parentheses.
return False

# TODO: Is this reasonable?
if last.type in COMPARATORS or last.type in MATH_OPERATORS:
return True

if (
last.type == token.RPAR
or last.type == token.RBRACE
Expand All @@ -6723,10 +6714,6 @@ def can_omit_invisible_parens(
# unnecessary.
return True

if line.magic_trailing_comma and penultimate.type == token.COMMA:
# The rightmost non-omitted bracket pair is the one we want to explode on.
return True

if _can_omit_closing_paren(line, last=last, line_length=line_length):
return True

Expand Down Expand Up @@ -6796,47 +6783,6 @@ def last_two_except(leaves: List[Leaf], omit: Collection[LeafID]) -> Tuple[Leaf,
raise LookupError("Last two leaves were also skipped")


def run_transformer(
line: Line,
transform: Transformer,
mode: Mode,
features: Collection[Feature],
*,
line_str: str = "",
) -> List[Line]:
if not line_str:
line_str = line_to_string(line)
result: List[Line] = []
for transformed_line in transform(line, features):
if str(transformed_line).strip("\n") == line_str:
raise CannotTransform("Line transformer returned an unchanged result")

result.extend(transform_line(transformed_line, mode=mode, features=features))

if not (
transform.__name__ == "rhs"
and line.bracket_tracker.invisible
and not any(bracket.value for bracket in line.bracket_tracker.invisible)
and not line.contains_multiline_strings()
and not result[0].contains_uncollapsable_type_comments()
and not result[0].contains_unsplittable_type_ignore()
and not is_line_short_enough(result[0], line_length=mode.line_length)
):
return result

line_copy = line.clone()
append_leaves(line_copy, line, line.leaves)
features_fop = set(features) | {Feature.FORCE_OPTIONAL_PARENTHESES}
second_opinion = run_transformer(
line_copy, transform, mode, features_fop, line_str=line_str
)
if all(
is_line_short_enough(ln, line_length=mode.line_length) for ln in second_opinion
):
result = second_opinion
return result


def get_cache_file(mode: Mode) -> Path:
return CACHE_DIR / f"cache.{mode.get_cache_key()}.pickle"

Expand Down
6 changes: 3 additions & 3 deletions src/black_primer/primer.json
Expand Up @@ -17,7 +17,7 @@
},
"bandersnatch": {
"cli_arguments": [],
"expect_formatting_changes": false,
"expect_formatting_changes": true,
"git_clone_url": "https://github.com/pypa/bandersnatch.git",
"long_checkout": false,
"py_versions": ["all"]
Expand All @@ -40,7 +40,7 @@
},
"flake8-bugbear": {
"cli_arguments": [],
"expect_formatting_changes": false,
"expect_formatting_changes": true,
"git_clone_url": "https://github.com/PyCQA/flake8-bugbear.git",
"long_checkout": false,
"py_versions": ["all"]
Expand Down Expand Up @@ -98,7 +98,7 @@
},
"sqlalchemy": {
"cli_arguments": [],
"expect_formatting_changes": false,
"expect_formatting_changes": true,
"git_clone_url": "https://github.com/sqlalchemy/sqlalchemy.git",
"long_checkout": false,
"py_versions": ["all"]
Expand Down
12 changes: 4 additions & 8 deletions tests/data/cantfit.py
Expand Up @@ -67,15 +67,11 @@
normal_name = (
but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying()
)
normal_name = (
but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying(
arg1, arg2, arg3
)
normal_name = but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying(
arg1, arg2, arg3
)
normal_name = (
but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying(
[1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3
)
normal_name = but_the_function_name_is_now_ridiculously_long_and_it_is_still_super_annoying(
[1, 2, 3], arg1, [1, 2, 3], arg2, [1, 2, 3], arg3
)
# long arguments
normal_name = normal_function_name(
Expand Down
7 changes: 3 additions & 4 deletions tests/data/collections.py
Expand Up @@ -148,10 +148,9 @@
print("foo %r", (foo.bar,))

if True:
IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = (
Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING
| {pylons.controllers.WSGIController}
)
IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING = Config.IGNORED_TYPES_FOR_ATTRIBUTE_CHECKING | {
pylons.controllers.WSGIController
}

if True:
ec2client.get_waiter("instance_stopped").wait(
Expand Down
34 changes: 17 additions & 17 deletions tests/data/composition.py
Expand Up @@ -39,9 +39,12 @@ def test(self) -> None:
# Only send the first n items.
items=items[:num_items]
)
return (
'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
% (test.name, test.filename, lineno, lname, err)
return 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s' % (
test.name,
test.filename,
lineno,
lname,
err,
)

def omitting_trailers(self) -> None:
Expand Down Expand Up @@ -165,17 +168,14 @@ def tricky_asserts(self) -> None:
_C.__init__.__code__.co_firstlineno + 1,
)

assert (
expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
)
assert expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
34 changes: 17 additions & 17 deletions tests/data/composition_no_trailing_comma.py
Expand Up @@ -225,9 +225,12 @@ def test(self) -> None:
# Only send the first n items.
items=items[:num_items]
)
return (
'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s'
% (test.name, test.filename, lineno, lname, err)
return 'Utterly failed doctest test for %s\n File "%s", line %s, in %s\n\n%s' % (
test.name,
test.filename,
lineno,
lname,
err,
)

def omitting_trailers(self) -> None:
Expand Down Expand Up @@ -351,17 +354,14 @@ def tricky_asserts(self) -> None:
_C.__init__.__code__.co_firstlineno + 1,
)

assert (
expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect
== {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}
)
assert expectedexpectedexpectedexpectedexpectedexpectedexpectedexpectedexpect == {
key1: value1,
key2: value2,
key3: value3,
key4: value4,
key5: value5,
key6: value6,
key7: value7,
key8: value8,
key9: value9,
}