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

Fix multiline docstring quote normalization #1637

Merged
merged 1 commit into from Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 7 additions & 0 deletions CHANGES.md
@@ -1,5 +1,12 @@
## Change Log

### Unreleased

#### _Black_

- `Black` now respects `--skip-string-normalization` when normalizing multiline
docstring quotes (#1637)

### 20.8b1

#### _Packaging_
Expand Down
7 changes: 7 additions & 0 deletions docs/change_log.md
Expand Up @@ -2,6 +2,13 @@

## Change Log

### Unreleased

#### _Black_

- `Black` now respects `--skip-string-normalization` when normalizing multiline
docstring quotes (#1637)

### 20.8b1

#### _Packaging_
Expand Down
1 change: 0 additions & 1 deletion src/black/__init__.py
Expand Up @@ -2050,7 +2050,6 @@ def visit_STRING(self, leaf: Leaf) -> Iterator[Line]:
if leaf.value[tail_len + 1] == docstring[-1]:
docstring = docstring + " "
leaf.value = leaf.value[0:lead_len] + docstring + leaf.value[tail_len:]
normalize_string_quotes(leaf)

yield from self.visit_default(leaf)

Expand Down
209 changes: 209 additions & 0 deletions tests/data/docstring_no_string_normalization.py
@@ -0,0 +1,209 @@
class ALonelyClass:
'''
A multiline class docstring.
'''
def AnEquallyLonelyMethod(self):
'''
A multiline method docstring'''
pass


def one_function():
'''This is a docstring with a single line of text.'''
pass


def shockingly_the_quotes_are_normalized():
'''This is a multiline docstring.
This is a multiline docstring.
This is a multiline docstring.
'''
pass


def foo():
"""This is a docstring with
some lines of text here
"""
return


def baz():
'''"This" is a string with some
embedded "quotes"'''
return


def poit():
"""
Lorem ipsum dolor sit amet.
Consectetur adipiscing elit:
- sed do eiusmod tempor incididunt ut labore
- dolore magna aliqua
- enim ad minim veniam
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass


def under_indent():
"""
These lines are indented in a way that does not
make sense.
"""
pass


def over_indent():
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass


def single_line():
"""But with a newline after it!
"""
pass


def this():
r"""
'hey ho'
"""


def that():
""" "hey yah" """


def and_that():
"""
"hey yah" """


def and_this():
'''
"hey yah"'''


def believe_it_or_not_this_is_in_the_py_stdlib(): '''
"hey yah"'''


def shockingly_the_quotes_are_normalized_v2():
'''
Docstring Docstring Docstring
'''
pass

# output

class ALonelyClass:
'''
A multiline class docstring.
'''

def AnEquallyLonelyMethod(self):
'''
A multiline method docstring'''
pass


def one_function():
'''This is a docstring with a single line of text.'''
pass


def shockingly_the_quotes_are_normalized():
'''This is a multiline docstring.
This is a multiline docstring.
This is a multiline docstring.
'''
pass


def foo():
"""This is a docstring with
some lines of text here
"""
return


def baz():
'''"This" is a string with some
embedded "quotes"'''
return


def poit():
"""
Lorem ipsum dolor sit amet.
Consectetur adipiscing elit:
- sed do eiusmod tempor incididunt ut labore
- dolore magna aliqua
- enim ad minim veniam
- quis nostrud exercitation ullamco laboris nisi
- aliquip ex ea commodo consequat
"""
pass


def under_indent():
"""
These lines are indented in a way that does not
make sense.
"""
pass


def over_indent():
"""
This has a shallow indent
- But some lines are deeper
- And the closing quote is too deep
"""
pass


def single_line():
"""But with a newline after it!"""
pass


def this():
r"""
'hey ho'
"""


def that():
""" "hey yah" """


def and_that():
"""
"hey yah" """


def and_this():
'''
"hey yah"'''


def believe_it_or_not_this_is_in_the_py_stdlib():
'''
"hey yah"'''


def shockingly_the_quotes_are_normalized_v2():
'''
Docstring Docstring Docstring
'''
pass
13 changes: 9 additions & 4 deletions tests/test_black.py
Expand Up @@ -517,11 +517,16 @@ def test_docstring(self) -> None:
self.assertFormatEqual(expected, actual)
black.assert_equivalent(source, actual)
black.assert_stable(source, actual, DEFAULT_MODE)

@patch("black.dump_to_file", dump_to_stderr)
def test_docstring_no_string_normalization(self) -> None:
"""Like test_docstring but with string normalization off."""
source, expected = read_data("docstring_no_string_normalization")
mode = replace(DEFAULT_MODE, string_normalization=False)
not_normalized = fs(source, mode=mode)
self.assertFormatEqual(expected, not_normalized)
black.assert_equivalent(source, not_normalized)
black.assert_stable(source, not_normalized, mode=mode)
actual = fs(source, mode=mode)
self.assertFormatEqual(expected, actual)
black.assert_equivalent(source, actual)
black.assert_stable(source, actual, mode)
Comment on lines +521 to +529
Copy link
Collaborator Author

@ichard26 ichard26 Aug 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a terrible diff that Git produced... 🙁


def test_long_strings(self) -> None:
"""Tests for splitting long strings."""
Expand Down