diff --git a/CHANGELOG.md b/CHANGELOG.md index 773f431..2c45716 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,8 @@ ### Changed -- For magic methods, such as `__init__`, `DCO011` code is now used. +- For `__init__` method, `DCO012` code is now used. +- For other magic methods, such as `__str__`, `DCO011` code is now used. ## [v1.3.0] - 2023-11-29 diff --git a/README.md b/README.md index e34456a..2480891 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,8 @@ The plugin adds the following configurations to `flake8`: A few rules have been defined to allow for selective suppression: - `DCO010`: docstring missing on a function/ method/ class. -- `DCO011`: docstring missing on a magic method. +- `DCO011`: docstring missing on a magic method, except `__init__`. +- `DCO012`: docstring missing on a `__init__` method. - `DCO020`: function/ method has one or more arguments and the docstring does not have an arguments section. - `DCO021`: function/ method with no arguments and the docstring has an @@ -189,6 +190,28 @@ class FooClass: This linting rule is triggered by a magic method without a docstring. For example: +```Python +class FooClass: + """Perform foo action.""" + def __str__(self): + return "Foo" +``` + +This example can be fixed by adding a docstring: + +```Python +class FooClass: + """Perform foo action.""" + def __str__(self): + """Perform foo action.""" + return "Foo" +``` + +### Fix DCO012 + +This linting rule is triggered by a `__init__` method without a docstring. For +example: + ```Python class FooClass: """Perform foo action.""" diff --git a/flake8_docstrings_complete/__init__.py b/flake8_docstrings_complete/__init__.py index 64967c3..50bbfd0 100644 --- a/flake8_docstrings_complete/__init__.py +++ b/flake8_docstrings_complete/__init__.py @@ -23,6 +23,11 @@ f"{MAGIC_METHOD_DOCSTR_MISSING_CODE} docstring should be defined for a magic method" f"{MORE_INFO_BASE}{MAGIC_METHOD_DOCSTR_MISSING_CODE.lower()}" ) +INIT_METHOD_DOCSTR_MISSING_CODE = f"{ERROR_CODE_PREFIX}012" +INIT_METHOD_DOCSTR_MISSING_MSG = ( + f"{INIT_METHOD_DOCSTR_MISSING_CODE} docstring should be defined for a __init__ method" + f"{MORE_INFO_BASE}{INIT_METHOD_DOCSTR_MISSING_CODE.lower()}" +) RETURNS_SECTION_NOT_IN_DOCSTR_CODE = f"{ERROR_CODE_PREFIX}030" RETURNS_SECTION_NOT_IN_DOCSTR_MSG = ( f"{RETURNS_SECTION_NOT_IN_DOCSTR_CODE} function/ method that returns a value should have the " @@ -365,11 +370,12 @@ def visit_any_function(self, node: ast.FunctionDef | ast.AsyncFunctionDef) -> No if not self._skip_function(node=node): # Check docstring is defined if ast.get_docstring(node) is None: - docstr_missing_msg = ( - MAGIC_METHOD_DOCSTR_MISSING_MSG - if node.name.startswith("__") and node.name.endswith("__") - else DOCSTR_MISSING_MSG - ) + if node.name == "__init__": + docstr_missing_msg = INIT_METHOD_DOCSTR_MISSING_MSG + elif node.name.startswith("__") and node.name.endswith("__"): + docstr_missing_msg = MAGIC_METHOD_DOCSTR_MISSING_MSG + else: + docstr_missing_msg = DOCSTR_MISSING_MSG self.problems.append( types_.Problem( lineno=node.lineno, col_offset=node.col_offset, msg=docstr_missing_msg diff --git a/tests/integration/test___init__.py b/tests/integration/test___init__.py index 066279b..7760657 100644 --- a/tests/integration/test___init__.py +++ b/tests/integration/test___init__.py @@ -14,6 +14,7 @@ FIXTURE_DECORATOR_PATTERN_DEFAULT, FIXTURE_FILENAME_PATTERN_ARG_NAME, FIXTURE_FILENAME_PATTERN_DEFAULT, + INIT_METHOD_DOCSTR_MISSING_CODE, MAGIC_METHOD_DOCSTR_MISSING_CODE, MULT_RETURNS_SECTIONS_IN_DOCSTR_CODE, MULT_YIELDS_SECTIONS_IN_DOCSTR_CODE, @@ -172,7 +173,7 @@ def foo(): # noqa: {DOCSTR_MISSING_CODE} f''' class Foo: """Docstring.""" - def __init__(): # noqa: {MAGIC_METHOD_DOCSTR_MISSING_CODE} + def __str__(): # noqa: {MAGIC_METHOD_DOCSTR_MISSING_CODE} pass ''', "source.py", @@ -181,6 +182,17 @@ def __init__(): # noqa: {MAGIC_METHOD_DOCSTR_MISSING_CODE} ), pytest.param( f''' +class Foo: + """Docstring.""" + def __init__(): # noqa: {INIT_METHOD_DOCSTR_MISSING_CODE} + pass +''', + "source.py", + "", + id=f"{INIT_METHOD_DOCSTR_MISSING_CODE} disabled", + ), + pytest.param( + f''' def foo(arg_1): """Docstring.""" # noqa: {ARGS_SECTION_NOT_IN_DOCSTR_CODE} ''', diff --git a/tests/unit/test___init__.py b/tests/unit/test___init__.py index 1476701..45c5436 100644 --- a/tests/unit/test___init__.py +++ b/tests/unit/test___init__.py @@ -6,6 +6,7 @@ from flake8_docstrings_complete import ( DOCSTR_MISSING_MSG, + INIT_METHOD_DOCSTR_MISSING_MSG, MAGIC_METHOD_DOCSTR_MISSING_MSG, MULT_RETURNS_SECTIONS_IN_DOCSTR_MSG, MULT_YIELDS_SECTIONS_IN_DOCSTR_MSG, @@ -501,14 +502,24 @@ def function_1(self): ''' class Class1: """Docstring.""" - def __init__(self): - return + def __str__(self): + return "Foo" ''', (f"4:4 {MAGIC_METHOD_DOCSTR_MISSING_MSG}",), id="magic method docstring missing return", ), pytest.param( ''' +class Class1: + """Docstring.""" + def __init__(self): + return +''', + (f"4:4 {INIT_METHOD_DOCSTR_MISSING_MSG}",), + id="__init__ method docstring missing return", + ), + pytest.param( + ''' def function_1(): """Docstring 1.""" return