def test_get_node_last_lineno_if_simple() -> None: node = astroid.extract_node(""" if True: print(1) pass """) assert utils.get_node_last_lineno(node) == 4
def test_get_node_last_lineno_method(self): node = astroid.extract_node(""" def x(a, b): print(a, b) pass """) assert get_node_last_lineno(node) == 4
def test_get_node_last_lineno_simple() -> None: node = astroid.extract_node( """ pass """ ) assert utils.get_node_last_lineno(node) == 2
def test_get_node_last_lineno_if_simple(self): node = astroid.extract_node(""" if True: print(1) pass """) assert get_node_last_lineno(node) == 4
def test_get_node_last_lineno_with(self): node = astroid.extract_node(""" with x as y: print(1) pass """) assert get_node_last_lineno(node) == 4
def test_get_node_last_lineno_method() -> None: node = astroid.extract_node(""" def x(a, b): print(a, b) pass """) assert utils.get_node_last_lineno(node) == 4
def test_get_node_last_lineno_with() -> None: node = astroid.extract_node(""" with x as y: print(1) pass """) assert utils.get_node_last_lineno(node) == 4
def test_get_node_last_lineno_simple(self): node = astroid.extract_node( """ pass """ ) assert get_node_last_lineno(node) == 2
def test_get_node_last_lineno_while_else(self): node = astroid.extract_node(""" while True: print(1) else: print(2) """) assert get_node_last_lineno(node) == 5
def test_get_node_last_lineno_for_else(self): node = astroid.extract_node(""" for x in range(0, 5): print(1) else: print(2) """) assert get_node_last_lineno(node) == 5
def test_get_node_last_lineno_while_else() -> None: node = astroid.extract_node(""" while True: print(1) else: print(2) """) assert utils.get_node_last_lineno(node) == 5
def test_get_node_last_lineno_for(): node = astroid.extract_node( """ for x in range(0, 5): print(1) """ ) assert utils.get_node_last_lineno(node) == 3
def test_get_node_last_lineno_decorator(self): node = astroid.extract_node(""" @decor() def x(a, b): print(a, b) pass """) assert get_node_last_lineno(node) == 5
def test_get_node_last_lineno_decorator() -> None: node = astroid.extract_node(""" @decor() def x(a, b): print(a, b) pass """) assert utils.get_node_last_lineno(node) == 5
def test_get_node_last_lineno_for_else() -> None: node = astroid.extract_node(""" for x in range(0, 5): print(1) else: print(2) """) assert utils.get_node_last_lineno(node) == 5
def test_get_node_last_lineno_while(): node = astroid.extract_node( """ while True: print(1) """ ) assert utils.get_node_last_lineno(node) == 3
def test_get_node_last_lineno_if_elseif_else(self): node = astroid.extract_node(""" if True: print(1) elif False: print(2) else: print(3) """) assert get_node_last_lineno(node) == 7
def test_get_node_last_lineno_if_elseif_else() -> None: node = astroid.extract_node(""" if True: print(1) elif False: print(2) else: print(3) """) assert utils.get_node_last_lineno(node) == 7
def test_get_node_last_lineno_try_except_finally(self): node = astroid.extract_node(""" try: print(1) except Exception: print(2) finally: print(4) """) assert get_node_last_lineno(node) == 7
def test_get_node_last_lineno_try(self): node = astroid.extract_node(""" try: print(1) except ValueError: print(2) except Exception: print(3) """) assert get_node_last_lineno(node) == 7
def _check_docstring( self, node_type: Literal["class", "function", "method", "module"], node, report_missing=True, confidence=interfaces.HIGH, ): """Check if the node has a non-empty docstring.""" docstring = node.doc_node.value if node.doc_node else None if docstring is None: docstring = _infer_dunder_doc_attribute(node) if docstring is None: if not report_missing: return lines = utils.get_node_last_lineno(node) - node.lineno if node_type == "module" and not lines: # If the module does not have a body, there's no reason # to require a docstring. return max_lines = self.linter.namespace.docstring_min_length if node_type != "module" and max_lines > -1 and lines < max_lines: return if node_type == "class": self.linter.stats.undocumented["klass"] += 1 else: self.linter.stats.undocumented[node_type] += 1 if (node.body and isinstance(node.body[0], nodes.Expr) and isinstance(node.body[0].value, nodes.Call)): # Most likely a string with a format call. Let's see. func = utils.safe_infer(node.body[0].value.func) if isinstance(func, astroid.BoundMethod) and isinstance( func.bound, astroid.Instance): # Strings. if func.bound.name in {"str", "unicode", "bytes"}: return if node_type == "module": message = "missing-module-docstring" elif node_type == "class": message = "missing-class-docstring" else: message = "missing-function-docstring" self.add_message(message, node=node, confidence=confidence) elif not docstring.strip(): if node_type == "class": self.linter.stats.undocumented["klass"] += 1 else: self.linter.stats.undocumented[node_type] += 1 self.add_message("empty-docstring", node=node, args=(node_type, ), confidence=confidence)
def test_get_node_last_lineno_try_except_else(self): node = astroid.extract_node(""" try: print(1) except Exception: print(2) print(3) else: print(4) """) assert get_node_last_lineno(node) == 8
def test_get_node_last_lineno_try_except_else_finally(): node = astroid.extract_node(""" try: print(1) except Exception: print(2) else: print(3) finally: print(4) """) assert utils.get_node_last_lineno(node) == 9
def test_get_node_last_lineno_class(self): node = astroid.extract_node(""" class C(object): CONST = True def x(self, b): print(b) def y(self): pass pass """) assert get_node_last_lineno(node) == 10
def _skip_func_docstring(self, node): """True either if the function `node` has a name matching the `no-docstring-rgx` pattern, or a docstring shorter than `docstring-min-length`; False otherwise. """ # skip functions that match the 'no-docstring-rgx' config option no_docstring_rgx = get_global_option(self, "no-docstring-rgx") if no_docstring_rgx and re.match(no_docstring_rgx, node.name): return True # skip functions smaller than 'docstring-min-length' lines = checker_utils.get_node_last_lineno(node) - node.lineno max_lines = get_global_option(self, "docstring-min-length") return max_lines > -1 and lines < max_lines
def test_get_node_last_lineno_combined(self): node = astroid.extract_node(""" class C(object): CONST = True def y(self): try: pass except: pass finally: pass """) assert get_node_last_lineno(node) == 11
def visit_functiondef(self, node: nodes.FunctionDef) -> None: """Called for function and method definitions (def). :param node: Node for a function or method definition in the AST :type node: :class:`astroid.scoped_nodes.Function` """ node_doc = utils.docstringify(node.doc, self.config.default_docstring_type) # skip functions that match the 'no-docstring-rgx' config option no_docstring_rgx = get_global_option(self, "no-docstring-rgx") if no_docstring_rgx and re.match(no_docstring_rgx, node.name): return # skip functions smaller than 'docstring-min-length' lines = checker_utils.get_node_last_lineno(node) - node.lineno max_lines = get_global_option(self, "docstring-min-length") if max_lines > -1 and lines < max_lines: return self.check_functiondef_params(node, node_doc) self.check_functiondef_returns(node, node_doc) self.check_functiondef_yields(node, node_doc)
def _check_docstring(self, node_type, node, report_missing=True, is_constructor=False): """Check function and module docstring to comply with standards :param node_type String: string type of the node (e.g. "module") :param node astroid.Node: ast node of the cheking :param report_missing bool: whether to error when docstring is missing :param is_constructor bool: whether the node is a constructor or not """ docstring = node.doc if docstring is None: if not report_missing: return if is_constructor and _extract_node_arg_names(node) == ['self']: # its ok to have empty contstructor doc if there are no arguments return lines = get_node_last_lineno(node) - node.lineno if node_type == "module" and not lines: # If the module has no body, there's no reason # to require a docstring. return max_lines = self.config.bc_docstring_min_length if node_type != "module" and max_lines > -1 and lines < max_lines: return if node.body and isinstance(node.body[0], astroid.Expr) and isinstance(node.body[0].value, astroid.Call): # Most likely a string with a format call. Let's see. func = safe_infer(node.body[0].value.func) if isinstance(func, astroid.BoundMethod) and isinstance( func.bound, astroid.Instance ): # Strings in Python 3, others in Python 2. if PY3K and func.bound.name == "str": return if func.bound.name in ("str", "unicode", "bytes"): return self.add_message( "bc-missing-docstring", node=node, args=(node_type,) ) elif not docstring.strip(): self.add_message( "bc-empty-docstring", node=node, args=(node_type,) ) else: if node_type == 'method': # Check if the "@staticmethod" decorator exists is_static_method = any(['staticmethod' in decoratorname for decoratorname in node.decoratornames()]) is_abstract_method = any(['abstractmethod' in decoratorname for decoratorname in node.decoratornames()]) if is_static_method: self._check_braincorp_docstring(docstring, _extract_node_arg_names(node), node, check_function_description=True, enforce_return_consistency=not is_abstract_method) else: self._check_braincorp_docstring(docstring, _extract_node_arg_names(node)[1:], node, check_function_description=not is_constructor, enforce_return_consistency=not is_abstract_method) elif node_type == 'function': self._check_braincorp_docstring(docstring, _extract_node_arg_names(node), node, check_function_description=True, enforce_return_consistency=True)