Skip to content
This repository has been archived by the owner on Nov 3, 2023. It is now read-only.

Change appropriate "Nested" definitions into "Inaccessible", and add new codes #561

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions docs/release_notes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ 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).
* Change handling of "inaccessible" functions and classes (#561).
* Replace D10X errors with D419 if docstring exists but is empty (#559).

Bug Fixes
Expand Down
6 changes: 4 additions & 2 deletions src/pydocstyle/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
Class,
Definition,
Function,
InaccessibleClass,
InaccessibleFunction,
Method,
Module,
NestedClass,
NestedFunction,
Package,
ParseError,
Parser,
Expand Down Expand Up @@ -204,6 +205,7 @@ def check_docstring_missing(self, definition, docstring):
Module: violations.D100,
Class: violations.D101,
NestedClass: violations.D106,
InaccessibleClass: violations.D121,
Method: lambda: violations.D105()
if definition.is_magic
else (
Expand All @@ -215,7 +217,7 @@ def check_docstring_missing(self, definition, docstring):
else None
)
),
NestedFunction: violations.D103,
InaccessibleFunction: violations.D123,
Function: (
lambda: violations.D103()
if not definition.is_overload
Expand Down
11 changes: 7 additions & 4 deletions src/pydocstyle/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ class ConfigurationParser:
)
BASE_ERROR_SELECTION_OPTIONS = ('ignore', 'select', 'convention')

DEFAULT_IGNORE = {"D121", "D123"}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other tools have this kind of "we have the ability to report these codes, but their off by default" functionality. I figured this belonged to that category. Note if people are selecting ignores today, this will no longer be the default.

DEFAULT_MATCH_RE = r'(?!test_).*\.py'
DEFAULT_MATCH_DIR_RE = r'[^\.].*'
DEFAULT_IGNORE_DECORATORS_RE = ''
Expand Down Expand Up @@ -599,10 +600,12 @@ def _get_exclusive_error_codes(cls, options):
if options.ignore is not None:
ignored = cls._expand_error_codes(options.ignore)
checked_codes = codes - ignored
elif options.select is not None:
checked_codes = cls._expand_error_codes(options.select)
elif options.convention is not None:
checked_codes = getattr(conventions, options.convention)
else:
codes -= cls.DEFAULT_IGNORE
if options.select is not None:
checked_codes = cls._expand_error_codes(options.select)
elif options.convention is not None:
checked_codes = getattr(conventions, options.convention)

# To not override the conventions nor the options - copy them.
return copy.deepcopy(checked_codes)
Expand Down
35 changes: 30 additions & 5 deletions src/pydocstyle/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,11 @@
'Module',
'Package',
'Function',
'NestedFunction',
'InaccessibleFunction',
'Method',
'Class',
'NestedClass',
'InaccessibleClass',
'AllError',
'StringIO',
'ParseError',
Expand Down Expand Up @@ -199,8 +200,9 @@ class Function(Definition):
"""A Python source code function."""

_nest = staticmethod(
lambda s: {'def': NestedFunction, 'class': NestedClass}[s]
lambda s: {'def': InaccessibleFunction, 'class': InaccessibleClass}[s]
)
is_accessible = True

@property
def is_public(self):
Expand Down Expand Up @@ -236,10 +238,18 @@ def is_test(self):
return self.name.startswith('test') or self.name == 'runTest'


class NestedFunction(Function):
"""A Python source code nested function."""
class InaccessibleFunction(Function):
"""A Python source code function which is inaccessible.

is_public = False
A function is inaccessible if it is defined inside another function.

Publicness is still evaluated based on the name, to allow devs to signal between public and
private if they so wish. (E.g. if a function returns another function, they may want the inner
function to be documented. Conversely a purely helper inner function might not need to be
documented)
"""

is_accessible = False


class Method(Function):
Expand Down Expand Up @@ -289,6 +299,7 @@ class Class(Definition):
_nest = staticmethod(lambda s: {'def': Method, 'class': NestedClass}[s])
is_public = Function.is_public
is_class = True
is_accessible = True


class NestedClass(Class):
Expand All @@ -304,6 +315,20 @@ def is_public(self):
)


class InaccessibleClass(Class):
"""A Python source code class, which is inaccessible.

An class is inaccessible if it is defined inside of a function.

Publicness is still evaluated based on the name, to allow devs to signal between public and
private if they so wish. (E.g. if a function returns a class, they may want the returned
class to be documented. Conversely a purely helper inner class might not need to be
documented)
"""

is_accessible = False


class Decorator(Value):
"""A decorator for function, method or class."""

Expand Down
8 changes: 8 additions & 0 deletions src/pydocstyle/violations.py
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,14 @@ def to_rst(cls) -> str:
'D107',
'Missing docstring in __init__',
)
D121 = D1xx.create_error(
'D121',
'Missing docstring in inaccessible public class',
)
D123 = D1xx.create_error(
'D123',
'Missing docstring in inaccessible public function',
)

D2xx = ErrorRegistry.create_group('D2', 'Whitespace Issues')
D200 = D2xx.create_error(
Expand Down
Loading