From f13fa75c18ad5b81aaa84f25b0b0f86a907af345 Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Wed, 26 Aug 2020 18:17:59 -0400 Subject: [PATCH] Fix multiline docstring quote normalization The quotes of multiline docstrings are now only normalized when string normalization is off, instead of the string normalization setting being ignored and the quotes being *always* normalized. I had to make a new test case and data file since the current pair for docstrings only worked when there is no formatting difference between the formatting results with string normalization on and off. I needed to add tests for when there *are* differences between the two. So I split test_docstring's test code when string normalization is disabled into a new test case along with a new data file. --- CHANGES.md | 7 + docs/change_log.md | 7 + src/black/__init__.py | 1 - .../data/docstring_no_string_normalization.py | 209 ++++++++++++++++++ tests/test_black.py | 13 +- 5 files changed, 232 insertions(+), 5 deletions(-) create mode 100644 tests/data/docstring_no_string_normalization.py diff --git a/CHANGES.md b/CHANGES.md index 11341779f58..7352b857075 100644 --- a/CHANGES.md +++ b/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_ diff --git a/docs/change_log.md b/docs/change_log.md index 658414bf967..b7337166659 100644 --- a/docs/change_log.md +++ b/docs/change_log.md @@ -2,6 +2,13 @@ ## Change Log +### Unreleased + +#### _Black_ + +- `Black` now respects `--skip-string-normalization` when normalizing multiline + docstring quotes (#1637) + ### 20.8b1 #### _Packaging_ diff --git a/src/black/__init__.py b/src/black/__init__.py index 200e31fd458..f325dfc92ad 100644 --- a/src/black/__init__.py +++ b/src/black/__init__.py @@ -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) diff --git a/tests/data/docstring_no_string_normalization.py b/tests/data/docstring_no_string_normalization.py new file mode 100644 index 00000000000..0457fcf114f --- /dev/null +++ b/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 diff --git a/tests/test_black.py b/tests/test_black.py index f5d4e1115a8..629afc5b0ad 100644 --- a/tests/test_black.py +++ b/tests/test_black.py @@ -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) def test_long_strings(self) -> None: """Tests for splitting long strings."""