From a8ff8a76a11fa4422a54e369d77b71d94d852334 Mon Sep 17 00:00:00 2001 From: Yilei Yang Date: Tue, 6 Sep 2022 17:35:14 -0700 Subject: [PATCH] Fix a crash when formatting some dicts with parenthesis-wrapped long string keys. --- CHANGES.md | 3 +++ src/black/trans.py | 10 ++++++++++ tests/data/preview/long_strings.py | 21 +++++++++++++++++++++ 3 files changed, 34 insertions(+) diff --git a/CHANGES.md b/CHANGES.md index 25c3d4889a0..147100c3012 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -14,6 +14,9 @@ +- Fix a crash when formatting some dicts with parenthesis-wrapped long string keys + (#3262) + ### Configuration diff --git a/src/black/trans.py b/src/black/trans.py index 7ecfcef703d..74b932bb422 100644 --- a/src/black/trans.py +++ b/src/black/trans.py @@ -1071,6 +1071,16 @@ def _prefer_paren_wrap_match(LL: List[Leaf]) -> Optional[int]: # And the string is surrounded by commas (or is the first/last child)... prev_sibling = LL[0].prev_sibling next_sibling = LL[0].next_sibling + if ( + not prev_sibling + and not next_sibling + and parent_type(LL[0]) == syms.atom + ): + # If it's an atom string, we need to check the parent atom's siblings. + parent = LL[0].parent + assert parent is not None # For type checkers. + prev_sibling = parent.prev_sibling + next_sibling = parent.next_sibling if (not prev_sibling or prev_sibling.type == token.COMMA) and ( not next_sibling or next_sibling.type == token.COMMA ): diff --git a/tests/data/preview/long_strings.py b/tests/data/preview/long_strings.py index 3ad5f355e33..6db3cfed9a9 100644 --- a/tests/data/preview/long_strings.py +++ b/tests/data/preview/long_strings.py @@ -18,6 +18,14 @@ D4 = {"A long and ridiculous {}".format(string_key): "This is a really really really long string that has to go i,side of a dictionary. It is soooo bad.", some_func("calling", "some", "stuff"): "This is a really really really long string that has to go inside of a dictionary. It is {soooo} bad (#{x}).".format(sooo="soooo", x=2), "A %s %s" % ("formatted", "string"): "This is a really really really long string that has to go inside of a dictionary. It is %s bad (#%d)." % ("soooo", 2)} +D5 = { # Test for https://github.com/psf/black/issues/3261 + ("This is a really long string that can't be expected to fit in one line and is used as a nested dict's key"): {"inner": "value"}, +} + +D6 = { # Test for https://github.com/psf/black/issues/3261 + ("This is a really long string that can't be expected to fit in one line and is used as a dict's key"): ["value1", "value2"], +} + L1 = ["The is a short string", "This is a really long string that can't possibly be expected to fit all together on one line. Also it is inside a list literal, so it's expected to be wrapped in parens when spliting to avoid implicit str concatenation.", short_call("arg", {"key": "value"}), "This is another really really (not really) long string that also can't be expected to fit on one line and is, like the other string, inside a list literal.", ("parens should be stripped for short string in list")] L2 = ["This is a really long string that can't be expected to fit in one line and is the only child of a list literal."] @@ -357,6 +365,19 @@ def foo(): % ("soooo", 2), } +D5 = { # Test for https://github.com/psf/black/issues/3261 + "This is a really long string that can't be expected to fit in one line and is used as a nested dict's key": { + "inner": "value" + }, +} + +D6 = { # Test for https://github.com/psf/black/issues/3261 + "This is a really long string that can't be expected to fit in one line and is used as a dict's key": [ + "value1", + "value2", + ], +} + L1 = [ "The is a short string", (