diff --git a/CHANGES.md b/CHANGES.md index 12a2d5fa064..7717898e95d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,8 @@ +- Fix unwanted crashes caused by AST equivalency check (#4290) + ### Preview style diff --git a/src/black/parsing.py b/src/black/parsing.py index aa97a8cecea..e8664b5ee23 100644 --- a/src/black/parsing.py +++ b/src/black/parsing.py @@ -223,11 +223,9 @@ def _stringify_ast(node: ast.AST, parent_stack: List[ast.AST]) -> Iterator[str]: and field == "value" and isinstance(value, str) and len(parent_stack) >= 2 + # Any standalone string, ideally this would + # exactly match black.nodes.is_docstring and isinstance(parent_stack[-1], ast.Expr) - and isinstance( - parent_stack[-2], - (ast.FunctionDef, ast.AsyncFunctionDef, ast.Module, ast.ClassDef), - ) ): # Constant strings may be indented across newlines, if they are # docstrings; fold spaces after newlines when comparing. Similarly, diff --git a/tests/test_black.py b/tests/test_black.py index ecea4a073a3..32a3b2a9dec 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -2908,6 +2908,22 @@ async def f(): """docstring""" ''', ) + self.check_ast_equivalence( + """ + if __name__ == "__main__": + " docstring-like " + """, + ''' + if __name__ == "__main__": + """docstring-like""" + ''', + ) + self.check_ast_equivalence(r'def f(): r" \n "', r'def f(): "\\n"') + self.check_ast_equivalence('try: pass\nexcept: " x "', 'try: pass\nexcept: "x"') + + self.check_ast_equivalence( + 'def foo(): return " x "', 'def foo(): return "x"', should_fail=True + ) def test_assert_equivalent_fstring(self) -> None: major, minor = sys.version_info[:2]