forked from PyCQA/flake8-docstrings
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathflake8_docstrings.py
144 lines (122 loc) · 4.25 KB
/
flake8_docstrings.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
"""Implementation of pydocstyle integration with Flake8.
pydocstyle docstrings convention needs error code and class parser for be
included as module into flake8
"""
import re
try:
import pydocstyle as pep257
module_name = "pydocstyle"
except ImportError:
import pep257
module_name = "pep257"
__version__ = "1.6.0"
__all__ = ("pep257Checker",)
class _ContainsAll:
def __contains__(self, code): # type: (str) -> bool
return True
class EnvironError(pep257.Error):
def __init__(self, err):
super().__init__(
code="D998",
short_desc="EnvironmentError: " + str(err),
context=None,
)
@property
def line(self):
"""Return 0 as line number for EnvironmentError."""
return 0
class AllError(pep257.Error):
def __init__(self, err):
super().__init__(
code="D999",
short_desc=str(err).partition("\n")[0],
context=None,
)
@property
def line(self):
"""pep257.AllError does not contain line number. Return 0 instead."""
return 0
class pep257Checker:
"""Flake8 needs a class to check python file."""
name = "flake8-docstrings"
version = f"{__version__}, {module_name}: {pep257.__version__}"
def __init__(self, tree, filename, lines):
"""Initialize the checker."""
self.tree = tree
self.filename = filename
self.checker = pep257.ConventionChecker()
self.source = "".join(lines)
@classmethod
def add_options(cls, parser):
"""Add plugin configuration option to flake8."""
parser.add_option(
"--docstring-convention",
action="store",
parse_from_config=True,
default="pep257",
choices=sorted(pep257.conventions) + ["all"],
help=(
"pydocstyle docstring convention, default 'pep257'. "
"Use the special value 'all' to enable all codes (note: "
"some codes are conflicting so you'll need to then exclude "
"those)."
),
)
parser.add_option(
"--ignore-decorators",
action="store",
parse_from_config=True,
default=None,
help=(
"pydocstyle ignore-decorators regular expression, "
"default None. "
"Ignore any functions or methods that are decorated by "
"a function with a name fitting this regular expression. "
"The default is not ignore any decorated functions. "
),
)
@classmethod
def parse_options(cls, options):
"""Parse the configuration options given to flake8."""
cls.convention = options.docstring_convention
cls.ignore_decorators = (
re.compile(options.ignore_decorators)
if options.ignore_decorators
else None
)
def _call_check_source(self):
try:
return self.checker.check_source(
self.source,
self.filename,
ignore_decorators=self.ignore_decorators,
ignore_inline_noqa=True,
)
except TypeError: # for versions of pydocstyle 5.1.1 and below
return self.checker.check_source(
self.source,
self.filename,
ignore_decorators=self.ignore_decorators,
)
def _check_source(self):
try:
for err in self._call_check_source():
yield err
except pep257.AllError as err:
yield AllError(err)
except OSError as err:
yield EnvironError(err)
def run(self):
"""Use directly check() api from pydocstyle."""
if self.convention == "all":
checked_codes = _ContainsAll()
else:
checked_codes = pep257.conventions[self.convention] | {
"D998",
"D999",
}
for error in self._check_source():
if isinstance(error, pep257.Error) and error.code in checked_codes:
# NOTE(sigmavirus24): Fixes GitLab#3
message = f"{error.code} {error.short_desc}"
yield (error.line, 0, message, type(self))