Repository: psf/black

Issue:
21.4b0 breaks syntax of string literals involving backslash preceded whitespace at end
**Describe the bug** A clear and concise description of what the bug is.

21.4b0 breaks syntax of string literals involving backslash preceded whitespace at end. Removing the whitespace may cause the backslash to escape the ending quote.

**To Reproduce** Steps to reproduce the behavior:

1. Take this file '...'
```python
def foo():
    """\ """
```
Also happens with single quotes, and raw strings.

2. Run _Black_ on it with these arguments '....'

Just the filename.

3. See error

```
error: cannot format t.py: INTERNAL ERROR: Black produced invalid code on pass 1: EOF while scanning triple-quoted string literal (<unknown>, line 2). Please report a bug on https://github.com/psf/black/issues.  This invalid output might be helpful: /tmp/blk_lwhtj4rf.log
Oh no! 💥 💔 💥
1 file failed to reformat.
```

```shellsession
$ cat /tmp/blk_lwhtj4rf.log
  File "/home/scop/.pyenv/versions/3.9.2/envs/bash-completion/lib/python3.9/site-packages/black/__init__.py", line 6508, in assert_equivalent
    dst_ast = parse_ast(dst)
  File "/home/scop/.pyenv/versions/3.9.2/envs/bash-completion/lib/python3.9/site-packages/black/__init__.py", line 6409, in parse_ast
    return ast27.parse(src)
  File "/home/scop/.pyenv/versions/3.9.2/envs/bash-completion/lib/python3.9/site-packages/typed_ast/ast27.py", line 50, in parse
    return _ast27.parse(source, filename, mode)
def foo():
    """\"""
```


**Expected behavior** A clear and concise description of what you expected to happen.

**Environment (please complete the following information):**

- Version: 21.4b0
- OS and Python version: Linux, 3.9.2

**Does this bug also happen on master?** To answer this, you have two options:

1. Use the online formatter at https://black.now.sh/?version=master, which will use the
   latest master branch.
2. Or run _Black_ on your machine:
   - create a new virtualenv (make sure it's the same Python version);
   - clone this repository;
   - run `pip install -e .[d,python2]`;
   - run `pip install -r test_requirements.txt`
   - make sure it's sane by running `python -m unittest`; and
   - run `black` like you did last time.

Does not seem to happen with the online version.

*Does* happen with current master set up using the above instructions.

**Additional context** Add any other context about the problem here.

`# fmt: skip` works around it


Discussion:

Resolving patch:
diff --git a/src/black/__init__.py b/src/black/__init__.py
--- a/src/black/__init__.py
+++ b/src/black/__init__.py
@@ -2186,7 +2186,13 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
                 if docstring[0] == quote_char:
                     docstring = " " + docstring
                 if docstring[-1] == quote_char:
-                    docstring = docstring + " "
+                    docstring += " "
+                if docstring[-1] == "\\":
+                    backslash_count = len(docstring) - len(docstring.rstrip("\\"))
+                    if backslash_count % 2:
+                        # Odd number of tailing backslashes, add some padding to
+                        # avoid escaping the closing string quote.
+                        docstring += " "
             else:
                 # Add some padding if the docstring is empty.
                 docstring = " "


Test patch:
diff --git a/tests/data/docstring.py b/tests/data/docstring.py
--- a/tests/data/docstring.py
+++ b/tests/data/docstring.py
@@ -158,6 +158,22 @@ def docstring_with_inline_tabs_and_tab_indentation():
 	"""
 	pass
 
+
+def backslash_space():
+    """\ """
+
+
+def multiline_backslash_1():
+  '''
+  hey\there\
+  \ '''
+
+
+def multiline_backslash_2():
+  '''
+  hey there \ '''
+
+
 # output
 
 class MyClass:
@@ -316,3 +332,18 @@ def docstring_with_inline_tabs_and_tab_indentation():
     line ends with some tabs
     """
     pass
+
+
+def backslash_space():
+    """\ """
+
+
+def multiline_backslash_1():
+    """
+  hey\there\
+  \ """
+
+
+def multiline_backslash_2():
+    """
+    hey there \ """