Repository: psf/black

Issue:
Unable to include empty docstring
Empty docstrings are used by sphinx to indicate methods that should not be included in the documentation. However, as of 21.4b0 black reformats empty docstrings to contain a space.

**To Reproduce**:
Source:
```
def foo():
    """"""
    ...
```

gets reformatted to

```
def foo():
    """ """
    ...
```

**Expected behavior** I'm generally supportive of the style changes introduced in #1740. However, in this case black is changing the code in a meaningful way. I suggest that empty docstrings be ignored as a special case. I am agnostic on whether the empty docstring should be spelled `""` or `""""""`.

**Environment:**

- Version: 21.4b2
- OS and Python version: debian 10/Python 3.7.10

**Does this bug also happen on master?** Yes




Discussion:
See #2150 for some similar previous discussion. I'm supportive of leaving empty docstrings alone to support this use case.
> See #2150 for some similar previous discussion. I'm supportive of leaving empty docstrings alone to support this use case.

If #2150 resolves in favor of reducing AST modifications that would certainly fix this bug. However a special case allowing empty docstrings would be sufficient for my use case.
This is impacting the urllib3 documentation, we use an empty docstring to avoid having subclass methods from Python's `http.client.HTTPConnection` that aren't relevant to our users show up in our documentation generated via autodoc.

Reference: https://github.com/urllib3/urllib3/pull/2239

Resolving patch:
diff --git a/src/black/linegen.py b/src/black/linegen.py
--- a/src/black/linegen.py
+++ b/src/black/linegen.py
@@ -236,6 +236,7 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
             # characters but only if they are the same as the first.
             quote_len = 1 if docstring[1] != quote_char else 3
             docstring = docstring[quote_len:-quote_len]
+            docstring_started_empty = not docstring
 
             if is_multiline_string(leaf):
                 indent = " " * 4 * self.current_line.depth
@@ -255,8 +256,7 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
                         # 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.
+            elif not docstring_started_empty:
                 docstring = " "
 
             # We could enforce triple quotes at this point.


Test patch:
diff --git a/tests/data/docstring.py b/tests/data/docstring.py
--- a/tests/data/docstring.py
+++ b/tests/data/docstring.py
@@ -102,7 +102,7 @@ def and_this():
   "hey yah"'''
 
 
-def empty():
+def multiline_whitespace():
     '''
     
     
@@ -111,11 +111,11 @@ def empty():
     '''
 
 
-def oneline_empty():
+def oneline_whitespace():
     '''      '''
 
 
-def oneline_nothing():
+def empty():
     """"""
 
 
@@ -293,16 +293,16 @@ def and_this():
     "hey yah"'''
 
 
-def empty():
+def multiline_whitespace():
     """ """
 
 
-def oneline_empty():
+def oneline_whitespace():
     """ """
 
 
-def oneline_nothing():
-    """ """
+def empty():
+    """"""
 
 
 def single_quotes():
@@ -374,4 +374,4 @@ def my_god_its_full_of_stars_1():
 
 # the space below is actually a \u2001, removed in output
 def my_god_its_full_of_stars_2():
-    "I'm sorry Dave"
\ No newline at end of file
+    "I'm sorry Dave"