|
17 | 17 | from pylint.checkers import utils |
18 | 18 | from pylint.checkers.base.basic_checker import _BasicChecker |
19 | 19 | from pylint.checkers.base.comparison_checker import ComparisonChecker |
| 20 | +from pylint.checkers.base.docstring_checker import DocStringChecker |
20 | 21 | from pylint.checkers.base.pass_checker import PassChecker |
21 | | -from pylint.checkers.utils import ( |
22 | | - infer_all, |
23 | | - is_overload_stub, |
24 | | - is_property_deleter, |
25 | | - is_property_setter, |
26 | | -) |
| 22 | +from pylint.checkers.utils import infer_all, is_property_deleter, is_property_setter |
27 | 23 | from pylint.reporters.ureports import nodes as reporter_nodes |
28 | 24 | from pylint.utils import LinterStats |
29 | 25 | from pylint.utils.utils import get_global_option |
@@ -132,8 +128,6 @@ class AnyStyle(NamingStyle): |
132 | 128 | ) |
133 | 129 | } |
134 | 130 |
|
135 | | -# do not require a doc string on private/system methods |
136 | | -NO_REQUIRED_DOC_RGX = re.compile("^_") |
137 | 131 | REVERSED_PROTOCOL_METHOD = "__reversed__" |
138 | 132 | SEQUENCE_PROTOCOL_METHODS = ("__getitem__", "__len__") |
139 | 133 | REVERSED_METHODS = (SEQUENCE_PROTOCOL_METHODS, (REVERSED_PROTOCOL_METHOD,)) |
@@ -2146,187 +2140,6 @@ def _check_typevar_variance(self, name: str, node: nodes.AssignName) -> None: |
2146 | 2140 | ) |
2147 | 2141 |
|
2148 | 2142 |
|
2149 | | -class DocStringChecker(_BasicChecker): |
2150 | | - msgs = { |
2151 | | - "C0112": ( |
2152 | | - "Empty %s docstring", |
2153 | | - "empty-docstring", |
2154 | | - "Used when a module, function, class or method has an empty " |
2155 | | - "docstring (it would be too easy ;).", |
2156 | | - {"old_names": [("W0132", "old-empty-docstring")]}, |
2157 | | - ), |
2158 | | - "C0114": ( |
2159 | | - "Missing module docstring", |
2160 | | - "missing-module-docstring", |
2161 | | - "Used when a module has no docstring." |
2162 | | - "Empty modules do not require a docstring.", |
2163 | | - {"old_names": [("C0111", "missing-docstring")]}, |
2164 | | - ), |
2165 | | - "C0115": ( |
2166 | | - "Missing class docstring", |
2167 | | - "missing-class-docstring", |
2168 | | - "Used when a class has no docstring." |
2169 | | - "Even an empty class must have a docstring.", |
2170 | | - {"old_names": [("C0111", "missing-docstring")]}, |
2171 | | - ), |
2172 | | - "C0116": ( |
2173 | | - "Missing function or method docstring", |
2174 | | - "missing-function-docstring", |
2175 | | - "Used when a function or method has no docstring." |
2176 | | - "Some special methods like __init__ do not require a " |
2177 | | - "docstring.", |
2178 | | - {"old_names": [("C0111", "missing-docstring")]}, |
2179 | | - ), |
2180 | | - } |
2181 | | - options = ( |
2182 | | - ( |
2183 | | - "no-docstring-rgx", |
2184 | | - { |
2185 | | - "default": NO_REQUIRED_DOC_RGX, |
2186 | | - "type": "regexp", |
2187 | | - "metavar": "<regexp>", |
2188 | | - "help": "Regular expression which should only match " |
2189 | | - "function or class names that do not require a " |
2190 | | - "docstring.", |
2191 | | - }, |
2192 | | - ), |
2193 | | - ( |
2194 | | - "docstring-min-length", |
2195 | | - { |
2196 | | - "default": -1, |
2197 | | - "type": "int", |
2198 | | - "metavar": "<int>", |
2199 | | - "help": ( |
2200 | | - "Minimum line length for functions/classes that" |
2201 | | - " require docstrings, shorter ones are exempt." |
2202 | | - ), |
2203 | | - }, |
2204 | | - ), |
2205 | | - ) |
2206 | | - |
2207 | | - def open(self): |
2208 | | - self.linter.stats.reset_undocumented() |
2209 | | - |
2210 | | - @utils.check_messages("missing-docstring", "empty-docstring") |
2211 | | - def visit_module(self, node: nodes.Module) -> None: |
2212 | | - self._check_docstring("module", node) |
2213 | | - |
2214 | | - @utils.check_messages("missing-docstring", "empty-docstring") |
2215 | | - def visit_classdef(self, node: nodes.ClassDef) -> None: |
2216 | | - if self.config.no_docstring_rgx.match(node.name) is None: |
2217 | | - self._check_docstring("class", node) |
2218 | | - |
2219 | | - @utils.check_messages("missing-docstring", "empty-docstring") |
2220 | | - def visit_functiondef(self, node: nodes.FunctionDef) -> None: |
2221 | | - if self.config.no_docstring_rgx.match(node.name) is None: |
2222 | | - ftype = "method" if node.is_method() else "function" |
2223 | | - if ( |
2224 | | - is_property_setter(node) |
2225 | | - or is_property_deleter(node) |
2226 | | - or is_overload_stub(node) |
2227 | | - ): |
2228 | | - return |
2229 | | - |
2230 | | - if isinstance(node.parent.frame(future=True), nodes.ClassDef): |
2231 | | - overridden = False |
2232 | | - confidence = ( |
2233 | | - interfaces.INFERENCE |
2234 | | - if utils.has_known_bases(node.parent.frame(future=True)) |
2235 | | - else interfaces.INFERENCE_FAILURE |
2236 | | - ) |
2237 | | - # check if node is from a method overridden by its ancestor |
2238 | | - for ancestor in node.parent.frame(future=True).ancestors(): |
2239 | | - if ancestor.qname() == "builtins.object": |
2240 | | - continue |
2241 | | - if node.name in ancestor and isinstance( |
2242 | | - ancestor[node.name], nodes.FunctionDef |
2243 | | - ): |
2244 | | - overridden = True |
2245 | | - break |
2246 | | - self._check_docstring( |
2247 | | - ftype, node, report_missing=not overridden, confidence=confidence # type: ignore[arg-type] |
2248 | | - ) |
2249 | | - elif isinstance(node.parent.frame(future=True), nodes.Module): |
2250 | | - self._check_docstring(ftype, node) # type: ignore[arg-type] |
2251 | | - else: |
2252 | | - return |
2253 | | - |
2254 | | - visit_asyncfunctiondef = visit_functiondef |
2255 | | - |
2256 | | - def _check_docstring( |
2257 | | - self, |
2258 | | - node_type: Literal["class", "function", "method", "module"], |
2259 | | - node, |
2260 | | - report_missing=True, |
2261 | | - confidence=interfaces.HIGH, |
2262 | | - ): |
2263 | | - """Check if the node has a non-empty docstring.""" |
2264 | | - docstring = node.doc_node.value if node.doc_node else None |
2265 | | - if docstring is None: |
2266 | | - docstring = _infer_dunder_doc_attribute(node) |
2267 | | - |
2268 | | - if docstring is None: |
2269 | | - if not report_missing: |
2270 | | - return |
2271 | | - lines = utils.get_node_last_lineno(node) - node.lineno |
2272 | | - |
2273 | | - if node_type == "module" and not lines: |
2274 | | - # If the module does not have a body, there's no reason |
2275 | | - # to require a docstring. |
2276 | | - return |
2277 | | - max_lines = self.config.docstring_min_length |
2278 | | - |
2279 | | - if node_type != "module" and max_lines > -1 and lines < max_lines: |
2280 | | - return |
2281 | | - if node_type == "class": |
2282 | | - self.linter.stats.undocumented["klass"] += 1 |
2283 | | - else: |
2284 | | - self.linter.stats.undocumented[node_type] += 1 |
2285 | | - if ( |
2286 | | - node.body |
2287 | | - and isinstance(node.body[0], nodes.Expr) |
2288 | | - and isinstance(node.body[0].value, nodes.Call) |
2289 | | - ): |
2290 | | - # Most likely a string with a format call. Let's see. |
2291 | | - func = utils.safe_infer(node.body[0].value.func) |
2292 | | - if isinstance(func, astroid.BoundMethod) and isinstance( |
2293 | | - func.bound, astroid.Instance |
2294 | | - ): |
2295 | | - # Strings. |
2296 | | - if func.bound.name in {"str", "unicode", "bytes"}: |
2297 | | - return |
2298 | | - if node_type == "module": |
2299 | | - message = "missing-module-docstring" |
2300 | | - elif node_type == "class": |
2301 | | - message = "missing-class-docstring" |
2302 | | - else: |
2303 | | - message = "missing-function-docstring" |
2304 | | - self.add_message(message, node=node, confidence=confidence) |
2305 | | - elif not docstring.strip(): |
2306 | | - if node_type == "class": |
2307 | | - self.linter.stats.undocumented["klass"] += 1 |
2308 | | - else: |
2309 | | - self.linter.stats.undocumented[node_type] += 1 |
2310 | | - self.add_message( |
2311 | | - "empty-docstring", node=node, args=(node_type,), confidence=confidence |
2312 | | - ) |
2313 | | - |
2314 | | - |
2315 | | -def _infer_dunder_doc_attribute(node): |
2316 | | - # Try to see if we have a `__doc__` attribute. |
2317 | | - try: |
2318 | | - docstring = node["__doc__"] |
2319 | | - except KeyError: |
2320 | | - return None |
2321 | | - |
2322 | | - docstring = utils.safe_infer(docstring) |
2323 | | - if not docstring: |
2324 | | - return None |
2325 | | - if not isinstance(docstring, nodes.Const): |
2326 | | - return None |
2327 | | - return docstring.value |
2328 | | - |
2329 | | - |
2330 | 2143 | def register(linter: "PyLinter") -> None: |
2331 | 2144 | linter.register_checker(BasicErrorChecker(linter)) |
2332 | 2145 | linter.register_checker(BasicChecker(linter)) |
|
0 commit comments