diff --git a/.github/workflows/do-release.yml b/.github/workflows/do-release.yml index 3777d91..b8560b2 100644 --- a/.github/workflows/do-release.yml +++ b/.github/workflows/do-release.yml @@ -116,8 +116,8 @@ jobs: - name: Get new version id: newversion run: | - pip install poetry - echo "::set-output name=version::$(echo $(poetry version | cut -d' ' -f2))" + pip install poetry + echo "::set-output name=version::$(echo $(poetry version | cut -d' ' -f2))" - name: Get next semantic version id: nextversion diff --git a/src/docformatter/format.py b/src/docformatter/format.py index 248a9fe..c28d24c 100644 --- a/src/docformatter/format.py +++ b/src/docformatter/format.py @@ -23,9 +23,11 @@ # SOFTWARE. """This module provides docformatter's Formattor class.""" + # Standard Library Imports import argparse import collections +import contextlib import io import tokenize from typing import TextIO, Tuple @@ -34,11 +36,10 @@ import untokenize # docformatter Package Imports +import docformatter.encode as _encode import docformatter.strings as _strings import docformatter.syntax as _syntax import docformatter.util as _util -import docformatter.encode as _encode - unicode = str @@ -327,6 +328,9 @@ def _format_code( modified_tokens.append( (token_type, token_string, start, end, line) ) + modified_tokens = self._do_remove_blank_lines_after_method( + modified_tokens + ) return untokenize.untokenize(modified_tokens) except tokenize.TokenError: @@ -446,6 +450,29 @@ def _do_format_docstring( ).strip() return f"{beginning}{summary_wrapped}{ending}" + def _do_remove_blank_lines_after_method(self, modified_tokens): + """Remove blank lines after method docstring. + + Parameters + ---------- + modified_tokens: list + The list of tokens created from the docstring. + + Returns + ------- + modified_tokens: list + The list of tokens with any blank lines following a method + docstring removed. + """ + with contextlib.suppress(IndexError): + if ( + modified_tokens[-1][4] == "\n" + and modified_tokens[-2][4].strip() == '"""' + and modified_tokens[-5][4].lstrip().startswith("def") + ): + modified_tokens.pop(-1) + return modified_tokens + def _do_strip_docstring(self, docstring: str) -> Tuple[str, str]: """Return contents of docstring and opening quote type. diff --git a/tests/test_format_code.py b/tests/test_format_code.py index 8859012..cb4b5ff 100644 --- a/tests/test_format_code.py +++ b/tests/test_format_code.py @@ -944,6 +944,53 @@ class TestClass: ''' ) + @pytest.mark.unit + @pytest.mark.parametrize("args", [[""]]) + def test_format_code_strip_blank_line_after_method_docstring( + self, + test_args, + args, + ): + """Strip any newlines after a method docstring. + + See issue #130 and requirement PEP_257_4.4. + """ + uut = Formatter( + test_args, + sys.stderr, + sys.stdin, + sys.stdout, + ) + + docstring = '''\ +class TestClass: + """This is a class docstring.""" + + def test_method(self): + """This is a method docstring. + + With a long description followed by two blank lines. + """ + pass +''' + assert docstring == uut._do_format_code( + '''\ +class TestClass: + + """This is a class docstring.""" + + def test_method(self): + + """This is a method docstring. + + With a long description followed by two blank lines. + """ + + + pass +''' +) + class TestFormatCodeRanges: """Class for testing _format_code() with the line_range or length_range