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

feat: format class attribute docstrings #116

Merged
merged 4 commits into from Aug 23, 2022
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
30 changes: 8 additions & 22 deletions .github/workflows/ci.yml
Expand Up @@ -27,7 +27,7 @@ jobs:
with:
python-version: "3.10"
- name: Install tox
run: python -m pip install tox
run: python -m pip install tox tox-gh-actions
- uses: actions/checkout@v3
with:
fetch-depth: 0
Expand All @@ -39,35 +39,21 @@ jobs:
run: tox -vv --notest
- name: Run tests with tox
run: tox -e py --skip-pkg-install
- name: Upload coverage data
uses: actions/upload-artifact@v3
- name: Create Coveralls coverage report
uses: miurahr/coveralls-python-action@patch-pyprject-toml
with:
name: coverage-data
path: ".tox/.coverage.*"
base-path: .tox
debug: true
parallel: true

upload_coveralls:
name: Upload Results to Coveralls
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-python@v4
with:
python-version: "3.10"
- name: Install tox
run: python -m pip install tox
- name: Setup coverage
run: tox -e coverage --notest
- name: Download coverage data
uses: actions/download-artifact@v3
with:
name: coverage-data
path: .tox
- name: Combine coverage reports
run: tox -e coverage
- name: Upload coverage report to Coveralls
uses: miurahr/coveralls-python-action@patch-pyprject-toml
with:
base-path: .tox
debug: true
parallel-finished: true
11 changes: 5 additions & 6 deletions docformatter.py
Expand Up @@ -553,7 +553,6 @@ def _format_code(
modified_tokens = []

sio = io.StringIO(source)
previous_token_string = ""
previous_token_type = None
only_comments_so_far = True

Expand All @@ -570,16 +569,15 @@ def _format_code(
and token_string.startswith(self.QUOTE_TYPES)
and (
previous_token_type == tokenize.INDENT
or previous_token_type == tokenize.NEWLINE
or only_comments_so_far
)
and is_in_range(self.args.line_range, start[0], end[0])
and has_correct_length(
self.args.length_range, start[0], end[0]
)
):
indentation = (
"" if only_comments_so_far else previous_token_string
)
indentation = " " * (len(line) - len(line.lstrip()))
token_string = self._do_format_docstring(
indentation,
token_string,
Expand All @@ -592,7 +590,6 @@ def _format_code(
]:
only_comments_so_far = False

previous_token_string = token_string
previous_token_type = token_type

# If the current token is a newline, the previous token was a
Expand Down Expand Up @@ -1139,13 +1136,15 @@ def normalize_summary(summary):
# remove trailing whitespace
summary = summary.rstrip()

# Add period at end of sentence
# Add period at end of sentence and capitalize the first word of the
# summary.
if (
summary
and (summary[-1].isalnum() or summary[-1] in ['"', "'"])
and (not summary.startswith("#"))
):
summary += "."
summary = summary[0].upper() + summary[1:]

return summary

Expand Down
9 changes: 9 additions & 0 deletions pyproject.toml
Expand Up @@ -184,6 +184,15 @@ isolated_build = true
skip_missing_interpreters = true
skipsdist = true

[gh-actions]
python =
3.6: py36
3.7: py37
3.8: py38
3.9: py39
3.10: py310
pypy-3.6: pypy3

[testenv]
description = run the test suite using pytest under {basepython}
deps =
Expand Down
27 changes: 27 additions & 0 deletions tests/test_format_code.py
Expand Up @@ -841,6 +841,33 @@ def test_format_code_no_docstring(self, test_args, args):
)
assert docstring == uut._do_format_code(docstring)

@pytest.mark.unit
@pytest.mark.parametrize("args", [[""]])
def test_format_code_class_docstring(self, test_args, args):
"""Format class docstring."""
uut = Formator(
test_args,
sys.stderr,
sys.stdin,
sys.stdout,
)

docstring = '''\
class TestClass:
"""This is a class docstring.

:cvar test_int: a class attribute.
..py.method: big_method()
"""
'''
assert docstring == uut._do_format_code('''\
class TestClass:
"""This is a class docstring.
:cvar test_int: a class attribute.
..py.method: big_method()
"""
''')


class TestFormatCodeRanges:
"""Class for testing _format_code() with the line_range or length_range
Expand Down
31 changes: 30 additions & 1 deletion tests/test_format_docstring.py
Expand Up @@ -839,7 +839,7 @@ def test_format_docstring_with_target_links(
"args",
[["--wrap-descriptions", "72", ""]],
)
def test_format_docstring_with_sinmple_link(
def test_format_docstring_with_simple_link(
self,
test_args,
args,
Expand Down Expand Up @@ -910,6 +910,35 @@ def test_format_docstring_with_short_link(
INDENTATION, docstring.strip()
)

@pytest.mark.unit
@pytest.mark.parametrize("args", [[""]])
def test_format_docstring_with_class_attributes(self, test_args, args):
"""Wrap long class attribute docstrings."""
uut = Formator(
test_args,
sys.stderr,
sys.stdin,
sys.stdout,
)

docstring = '''\
class TestClass:
"""This is a class docstring."""

test_int = 1
"""This is a very, very, very long docstring that should really be
reformatted nicely by docformatter."""
'''
assert docstring == uut._do_format_code(
'''\
class TestClass:
"""This is a class docstring."""

test_int = 1
"""This is a very, very, very long docstring that should really be reformatted nicely by docformatter."""
'''
)


class TestFormatStyleOptions:
"""Class for testing format_docstring() when requesting style options."""
Expand Down
17 changes: 17 additions & 0 deletions tests/test_string_functions.py
Expand Up @@ -189,6 +189,23 @@ def test_normalize_summary_formatted_as_title(self):
summary = "# This is a title"
assert summary == docformatter.normalize_summary(summary)

@pytest.mark.unit
def test_normalize_summary_capitalize_first_letter(self):
"""Capitalize the first letter of the summary.

See issue #76. See requirement docformatter_4.5.1.
"""
assert (
"This is a summary that needs to be capped."
== docformatter.normalize_summary(
"this is a summary that needs to be capped"
)
)

assert "Don't lower case I'm." == docformatter.normalize_summary(
"don't lower case I'm"
)


class TestSplitters:
"""Class for testing the string splitting function.
Expand Down