From ad5c315ddad26a3c41f22d3b73c493fb7d7b86b8 Mon Sep 17 00:00:00 2001 From: Richard Si <63936253+ichard26@users.noreply.github.com> Date: Thu, 14 Jul 2022 19:47:33 -0400 Subject: [PATCH] Actually disable docstring prefix normalization with -S + fix instability (#3168) The former was a regression I introduced a long time ago. To avoid changing the stable style too much, the regression is only fixed if --preview is enabled Annoyingly enough, as we currently always enforce a second format pass if changes were made, there's no good way to prove the existence of the docstring quote normalization instability issue. For posterity, here's one failing example: --- source +++ first pass @@ -1,7 +1,7 @@ def some_function(self): - '''' + """ ' - ''' + """ pass --- first pass +++ second pass @@ -1,7 +1,7 @@ def some_function(self): - """ ' + """' """ pass Co-authored-by: Jelle Zijlstra --- CHANGES.md | 2 ++ src/black/linegen.py | 19 ++++++++++++++++++- src/black/mode.py | 7 ++++--- ...cstring_preview_no_string_normalization.py | 10 ++++++++++ tests/data/simple_cases/docstring.py | 14 ++++++++++++++ tests/test_format.py | 12 ++++++++++++ 6 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 tests/data/miscellaneous/docstring_preview_no_string_normalization.py diff --git a/CHANGES.md b/CHANGES.md index 7d2e0bc..8543a8d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -19,6 +19,8 @@ - Single-character closing docstring quotes are no longer moved to their own line as this is invalid. This was a bug introduced in version 22.6.0. (#3166) +- `--skip-string-normalization` / `-S` now prevents docstring prefixes from being + normalized as expected (#3168) ### _Blackd_ diff --git a/src/black/linegen.py b/src/black/linegen.py index 20f3ac6..1f132b7 100644 --- a/src/black/linegen.py +++ b/src/black/linegen.py @@ -293,7 +293,24 @@ class LineGenerator(Visitor[Line]): if is_docstring(leaf) and "\\\n" not in leaf.value: # We're ignoring docstrings with backslash newline escapes because changing # indentation of those changes the AST representation of the code. - docstring = normalize_string_prefix(leaf.value) + if Preview.normalize_docstring_quotes_and_prefixes_properly in self.mode: + # There was a bug where --skip-string-normalization wouldn't stop us + # from normalizing docstring prefixes. To maintain stability, we can + # only address this buggy behaviour while the preview style is enabled. + if self.mode.string_normalization: + docstring = normalize_string_prefix(leaf.value) + # visit_default() does handle string normalization for us, but + # since this method acts differently depending on quote style (ex. + # see padding logic below), there's a possibility for unstable + # formatting as visit_default() is called *after*. To avoid a + # situation where this function formats a docstring differently on + # the second pass, normalize it early. + docstring = normalize_string_quotes(docstring) + else: + docstring = leaf.value + else: + # ... otherwise, we'll keep the buggy behaviour >.< + docstring = normalize_string_prefix(leaf.value) prefix = get_string_prefix(docstring) docstring = docstring[len(prefix) :] # Remove the prefix quote_char = docstring[0] diff --git a/src/black/mode.py b/src/black/mode.py index 896c516..b7359fa 100644 --- a/src/black/mode.py +++ b/src/black/mode.py @@ -145,12 +145,13 @@ def supports_feature(target_versions: Set[TargetVersion], feature: Feature) -> b class Preview(Enum): """Individual preview style features.""" - string_processing = auto() - remove_redundant_parens = auto() - one_element_subscript = auto() annotation_parens = auto() long_docstring_quotes_on_newline = auto() + normalize_docstring_quotes_and_prefixes_properly = auto() + one_element_subscript = auto() remove_block_trailing_newline = auto() + remove_redundant_parens = auto() + string_processing = auto() class Deprecated(UserWarning): diff --git a/tests/data/miscellaneous/docstring_preview_no_string_normalization.py b/tests/data/miscellaneous/docstring_preview_no_string_normalization.py new file mode 100644 index 0000000..0957231 --- /dev/null +++ b/tests/data/miscellaneous/docstring_preview_no_string_normalization.py @@ -0,0 +1,10 @@ +def do_not_touch_this_prefix(): + R"""There was a bug where docstring prefixes would be normalized even with -S.""" + + +def do_not_touch_this_prefix2(): + F'There was a bug where docstring prefixes would be normalized even with -S.' + + +def do_not_touch_this_prefix3(): + uR'''There was a bug where docstring prefixes would be normalized even with -S.''' diff --git a/tests/data/simple_cases/docstring.py b/tests/data/simple_cases/docstring.py index 7153be4..f08bba5 100644 --- a/tests/data/simple_cases/docstring.py +++ b/tests/data/simple_cases/docstring.py @@ -209,6 +209,13 @@ def multiline_docstring_at_line_limit(): second line----------------------------------------------------------------------""" +def stable_quote_normalization_with_immediate_inner_single_quote(self): + '''' + + + ''' + + # output class MyClass: @@ -417,3 +424,10 @@ def multiline_docstring_at_line_limit(): """first line----------------------------------------------------------------------- second line----------------------------------------------------------------------""" + + +def stable_quote_normalization_with_immediate_inner_single_quote(self): + """' + + + """ diff --git a/tests/test_format.py b/tests/test_format.py index 0e1059c..86339f2 100644 --- a/tests/test_format.py +++ b/tests/test_format.py @@ -139,6 +139,18 @@ def test_docstring_no_string_normalization() -> None: assert_format(source, expected, mode) +def test_preview_docstring_no_string_normalization() -> None: + """ + Like test_docstring but with string normalization off *and* the preview style + enabled. + """ + source, expected = read_data( + "miscellaneous", "docstring_preview_no_string_normalization" + ) + mode = replace(DEFAULT_MODE, string_normalization=False, preview=True) + assert_format(source, expected, mode) + + def test_long_strings_flag_disabled() -> None: """Tests for turning off the string processing logic.""" source, expected = read_data("miscellaneous", "long_strings_flag_disabled") -- 2.39.2