From 013f8e2c4b6c01c9f1337e009c787b59a68d47fa Mon Sep 17 00:00:00 2001 From: Sambhav Kothari Date: Thu, 30 Dec 2021 20:31:50 +0000 Subject: [PATCH 1/4] Fix CI for python 3.10 (#565) --- requirements/tests.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/requirements/tests.txt b/requirements/tests.txt index 42538dd4..d6bf398b 100644 --- a/requirements/tests.txt +++ b/requirements/tests.txt @@ -1,4 +1,6 @@ pytest==6.2.5 -mypy==0.782 -black==20.8b1 +mypy==0.930 +black==21.12b0 isort==5.4.2 +types-toml +types-setuptools From 07fa8359b40861bdb62f0500cdd1f0166e2e20f7 Mon Sep 17 00:00:00 2001 From: Sambhav Kothari Date: Thu, 30 Dec 2021 20:34:36 +0000 Subject: [PATCH 2/4] Remove tests for python 3.6 from CI Python 3.6 reached EOL 5 years ago and stopped receiving security updates last week. Dropping it from CI to speed up PR checks. See https://endoflife.date/python --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 8808fb78..9fe23070 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: os: [macos-latest, ubuntu-latest, windows-latest] - python-version: ["3.6", "3.7", "3.8", "3.9", "3.10"] + python-version: ["3.7", "3.8", "3.9", "3.10"] steps: - uses: actions/checkout@v2 From 8dee619363f1080419178eb76cb16f267128847c Mon Sep 17 00:00:00 2001 From: Joshua Cannon Date: Thu, 30 Dec 2021 14:39:25 -0600 Subject: [PATCH 3/4] Add D419: Add and switch to "Docstring is empty" error code (#559) Co-authored-by: Sambhav Kothari --- docs/release_notes.rst | 1 + src/pydocstyle/checker.py | 19 +++++++++++++------ src/pydocstyle/violations.py | 4 ++++ src/tests/test_cases/capitalization.py | 2 +- src/tests/test_cases/test.py | 6 +++--- 5 files changed, 22 insertions(+), 10 deletions(-) diff --git a/docs/release_notes.rst b/docs/release_notes.rst index 72332114..b70aca01 100644 --- a/docs/release_notes.rst +++ b/docs/release_notes.rst @@ -12,6 +12,7 @@ New Features * Add support for `property_decorators` config to ignore D401. * Add support for Python 3.10 (#554). +* Replace D10X errors with D419 if docstring exists but is empty (#559). 6.1.1 - May 17th, 2021 --------------------------- diff --git a/src/pydocstyle/checker.py b/src/pydocstyle/checker.py index be74867f..5c5522e7 100644 --- a/src/pydocstyle/checker.py +++ b/src/pydocstyle/checker.py @@ -196,12 +196,7 @@ def check_docstring_missing(self, definition, docstring): with a single underscore. """ - if ( - not docstring - and definition.is_public - or docstring - and is_blank(ast.literal_eval(docstring)) - ): + if not docstring and definition.is_public: codes = { Module: violations.D100, Class: violations.D101, @@ -227,6 +222,18 @@ def check_docstring_missing(self, definition, docstring): } return codes[type(definition)]() + @check_for(Definition, terminal=True) + def check_docstring_empty(self, definition, docstring): + """D419: Docstring is empty. + + If the user provided a docstring but it was empty, it is like they never provided one. + + NOTE: This used to report as D10X errors. + + """ + if docstring and is_blank(ast.literal_eval(docstring)): + return violations.D419() + @check_for(Definition) def check_one_liners(self, definition, docstring): """D200: One-liner docstrings should fit on one line with quotes. diff --git a/src/pydocstyle/violations.py b/src/pydocstyle/violations.py index 60fc064e..8156921a 100644 --- a/src/pydocstyle/violations.py +++ b/src/pydocstyle/violations.py @@ -415,6 +415,10 @@ def to_rst(cls) -> str: 'D418', 'Function/ Method decorated with @overload shouldn\'t contain a docstring', ) +D419 = D4xx.create_error( + 'D419', + 'Docstring is empty', +) class AttrDict(dict): diff --git a/src/tests/test_cases/capitalization.py b/src/tests/test_cases/capitalization.py index 91ecf45c..a15c79f3 100644 --- a/src/tests/test_cases/capitalization.py +++ b/src/tests/test_cases/capitalization.py @@ -13,7 +13,7 @@ def not_capitalized(): # Make sure empty docstrings don't generate capitalization errors. -@expect("D103: Missing docstring in public function") +@expect("D419: Docstring is empty") def empty_docstring(): """""" diff --git a/src/tests/test_cases/test.py b/src/tests/test_cases/test.py index 8154c960..1cbd8ec4 100644 --- a/src/tests/test_cases/test.py +++ b/src/tests/test_cases/test.py @@ -13,7 +13,7 @@ class class_: - expect('meta', 'D106: Missing docstring in public nested class') + expect('meta', 'D419: Docstring is empty') class meta: """""" @@ -64,13 +64,13 @@ def __call__(self=None, x=None, y=None, z=None): pass -@expect('D103: Missing docstring in public function') +@expect('D419: Docstring is empty') def function(): """ """ def ok_since_nested(): pass - @expect('D103: Missing docstring in public function') + @expect('D419: Docstring is empty') def nested(): '' From 1011866e6ea91a1fbcb4b01520d2a348becc7de1 Mon Sep 17 00:00:00 2001 From: Ryan Morshead Date: Thu, 30 Dec 2021 12:46:42 -0800 Subject: [PATCH 4/4] Allow for hanging indent when documenting args in Google style (#564) Co-authored-by: Ryan Morshead Co-authored-by: Sambhav Kothari --- docs/release_notes.rst | 1 + src/pydocstyle/checker.py | 35 ++++++++++++++++++++++++++++++-- src/tests/test_cases/sections.py | 5 +---- 3 files changed, 35 insertions(+), 6 deletions(-) diff --git a/docs/release_notes.rst b/docs/release_notes.rst index b70aca01..5da4b27d 100644 --- a/docs/release_notes.rst +++ b/docs/release_notes.rst @@ -10,6 +10,7 @@ Current Development Version New Features +* Allow for hanging indent when documenting args in Google style. (#449) * Add support for `property_decorators` config to ignore D401. * Add support for Python 3.10 (#554). * Replace D10X errors with D419 if docstring exists but is empty (#559). diff --git a/src/pydocstyle/checker.py b/src/pydocstyle/checker.py index 5c5522e7..0b456444 100644 --- a/src/pydocstyle/checker.py +++ b/src/pydocstyle/checker.py @@ -6,6 +6,7 @@ from collections import namedtuple from itertools import chain, takewhile from re import compile as re +from textwrap import dedent from . import violations from .config import IllegalConfiguration @@ -122,6 +123,8 @@ class ConventionChecker: r"\s*" # Followed by a colon r":" + # Might have a new line and leading whitespace + r"\n?\s*" # Followed by 1 or more characters - which is the docstring for the parameter ".+" ) @@ -843,10 +846,38 @@ def _check_args_section(docstring, definition, context): * The section documents all function arguments (D417) except `self` or `cls` if it is a method. + Documentation for each arg should start at the same indentation + level. For example, in this case x and y are distinguishable:: + + Args: + x: Lorem ipsum dolor sit amet + y: Ut enim ad minim veniam + + In the case below, we only recognize x as a documented parameter + because the rest of the content is indented as if it belongs + to the description for x:: + + Args: + x: Lorem ipsum dolor sit amet + y: Ut enim ad minim veniam """ docstring_args = set() - for line in context.following_lines: - match = ConventionChecker.GOOGLE_ARGS_REGEX.match(line) + # normalize leading whitespace + args_content = dedent("\n".join(context.following_lines)).strip() + + args_sections = [] + for line in args_content.splitlines(keepends=True): + if not line[:1].isspace(): + # This line is the start of documentation for the next + # parameter because it doesn't start with any whitespace. + args_sections.append(line) + else: + # This is a continuation of documentation for the last + # parameter because it does start with whitespace. + args_sections[-1] += line + + for section in args_sections: + match = ConventionChecker.GOOGLE_ARGS_REGEX.match(section) if match: docstring_args.add(match.group(1)) yield from ConventionChecker._check_missing_args( diff --git a/src/tests/test_cases/sections.py b/src/tests/test_cases/sections.py index d671102b..b4932606 100644 --- a/src/tests/test_cases/sections.py +++ b/src/tests/test_cases/sections.py @@ -367,10 +367,7 @@ def test_missing_docstring(a, b): # noqa: D213, D407 """ @staticmethod - @expect("D417: Missing argument descriptions in the docstring " - "(argument(s) skip, verbose are missing descriptions in " - "'test_missing_docstring_another' docstring)", arg_count=2) - def test_missing_docstring_another(skip, verbose): # noqa: D213, D407 + def test_hanging_indent(skip, verbose): # noqa: D213, D407 """Do stuff. Args: