diff -r c6011e501282 -r 4573827e9815 src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/DocStyle/DocStyleChecker.py --- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/DocStyle/DocStyleChecker.py Sun Dec 17 17:15:19 2023 +0100 +++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/DocStyle/DocStyleChecker.py Mon Dec 18 16:39:01 2023 +0100 @@ -33,9 +33,12 @@ """ Constructor - @param source source code of the context (list of string or string) - @param startLine line number the context starts in the source (integer) - @param contextType type of the context object (string) + @param source source code of the context + @type list of str or str + @param startLine line number the context starts in the source + @type int + @param contextType type of the context object + @type str """ if isinstance(source, str): self.__source = source.splitlines(True) @@ -55,7 +58,8 @@ """ Public method to get the source. - @return source (list of string) + @return source + @rtype list of str """ return self.__source @@ -63,7 +67,8 @@ """ Public method to get the joined source lines. - @return source (string) + @return source + @rtype str """ return "".join(self.__source) @@ -71,7 +76,8 @@ """ Public method to get the start line number. - @return start line number (integer) + @return start line number + @rtype int """ return self.__start @@ -79,7 +85,8 @@ """ Public method to get the end line number. - @return end line number (integer) + @return end line number + @rtype int """ return self.__start + len(self.__source) - 1 @@ -87,7 +94,8 @@ """ Public method to get the indentation of the first line. - @return indentation string (string) + @return indentation string + @rtype str """ return self.__indent @@ -95,7 +103,8 @@ """ Public method to get the context type. - @return context type (string) + @return context type + @rtype str """ return self.__type @@ -175,6 +184,8 @@ "D261", "D262", "D263", + "D270", + "D271", ] def __init__( @@ -191,16 +202,22 @@ """ Constructor - @param source source code to be checked (list of string) - @param filename name of the source file (string) - @param select list of selected codes (list of string) - @param ignore list of codes to be ignored (list of string) - @param expected list of expected codes (list of string) + @param source source code to be checked + @type list of str + @param filename name of the source file + @type str + @param select list of selected codes + @type list of str + @param ignore list of codes to be ignored + @type list of str + @param expected list of expected codes + @type list of str @param repeat flag indicating to report each occurrence of a code - (boolean) - @param maxLineLength allowed line length (integer) - @param docType type of the documentation strings - (string, one of 'eric' or 'pep257') + @type bool + @param maxLineLength allowed line length + @type int + @param docType type of the documentation strings (one of 'eric' or 'pep257') + @type str """ self.__select = tuple(select) self.__ignore = ("",) if select else tuple(ignore) @@ -296,6 +313,8 @@ ("D244", "D245"), ), (self.__checkEricException, ("D250", "D251", "D252", "D253")), + (self.__checkEricDocumentationSequence, ("D270",)), + (self.__checkEricDocumentationDeprecatedTags, ("D271",)), ], "docstring": [ (self.__checkTripleDoubleQuotes, ("D111",)), @@ -321,8 +340,10 @@ """ Private method to check if the error code should be ignored. - @param code message code to check for (string) - @return flag indicating to ignore the given code (boolean) + @param code message code to check for + @type str + @return flag indicating to ignore the given code + @rtype bool """ return code.startswith(self.__ignore) and not code.startswith(self.__select) @@ -330,10 +351,14 @@ """ Private method to record an issue. - @param lineNumber line number of the issue (integer) - @param offset position within line of the issue (integer) - @param code message code (string) - @param args arguments for the message (list) + @param lineNumber line number of the issue + @type int + @param offset position within line of the issue + @type int + @param code message code + @type str + @param args arguments for the message + @type list """ if self.__ignoreCode(code): return @@ -369,7 +394,8 @@ """ Private method to get the next line from the source. - @return next line of source (string) + @return next line of source + @rtype str """ self.__lineNumber += 1 if self.__lineNumber > len(self.__source): @@ -400,8 +426,10 @@ """ Private method to extract the summary line. - @param docstringContext docstring context (DocStyleContext) - @return summary line (string) and the line it was found on (integer) + @param docstringContext docstring context + @type DocStyleContext + @return summary line (string) and the line it was found on + @rtype int """ lines = docstringContext.source() @@ -424,9 +452,10 @@ """ Private method to extract the summary lines. - @param docstringContext docstring context (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext @return summary lines (list of string) and the line it was found on - (integer) + @rtype int """ summaries = [] lines = docstringContext.source() @@ -473,8 +502,10 @@ Private method to get the argument names of a function node. @param node AST node to extract arguments names from + @type ast.AST @return tuple of two list of argument names, one for arguments - and one for keyword arguments (tuple of list of string) + and one for keyword arguments + @rtype tuple of (list of str, list of str) """ arguments = [] arguments.extend([arg.arg for arg in node.args.args]) @@ -495,8 +526,10 @@ """ Private method to extract a docstring given a module source. - @param source source to parse (list of string) - @return context of extracted docstring (DocStyleContext) + @param source source to parse + @type list of str + @return context of extracted docstring + @rtype DocStyleContext """ for kind, value, (line, _char), _, _ in tokenize.generate_tokens( StringIO("".join(source)).readline @@ -514,9 +547,12 @@ """ Private method to extract a docstring given `def` or `class` source. - @param context context data to get the docstring from (DocStyleContext) - @param what string denoting what is being parsed (string) - @return context of extracted docstring (DocStyleContext) + @param context context data to get the docstring from + @type DocStyleContext + @param what string denoting what is being parsed + @type str + @return context of extracted docstring + @rtype DocStyleContext """ moduleDocstring = self.__parseModuleDocstring(context.source()) if what.startswith("module") or context.contextType() == "module": @@ -539,8 +575,10 @@ """ Private method to extract top-level functions or classes. - @param keyword keyword signaling what to extract (string) - @return extracted function or class contexts (list of DocStyleContext) + @param keyword keyword signaling what to extract + @type str + @return extracted function or class contexts + @rtype list of DocStyleContext """ self.__resetReadline() tokenGenerator = tokenize.generate_tokens(self.__readline) @@ -565,7 +603,8 @@ """ Private method to extract top-level functions. - @return extracted function contexts (list of DocStyleContext) + @return extracted function contexts + @rtype list of DocStyleContext """ if not self.__functionsCache: self.__functionsCache = self.__parseTopLevel("def") @@ -575,7 +614,8 @@ """ Private method to extract top-level classes. - @return extracted class contexts (list of DocStyleContext) + @return extracted class contexts + @rtype list of DocStyleContext """ if not self.__classesCache: self.__classesCache = self.__parseTopLevel("class") @@ -586,7 +626,9 @@ Private method to skip over an indented block of source code. @param tokenGenerator token generator + @type str iterator @return last token of the indented block + @rtype tuple """ kind, value, start, end, raw = next(tokenGenerator) while kind != tokenize.INDENT: @@ -606,7 +648,8 @@ """ Private method to extract methods of all classes. - @return extracted method contexts (list of DocStyleContext) + @return extracted method contexts + @rtype list of DocStyleContext """ if not self.__methodsCache: contexts = [] @@ -644,8 +687,10 @@ """ Private method to extract a context from the source. - @param kind kind of context to extract (string) - @return requested contexts (list of DocStyleContext) + @param kind kind of context to extract + @type str + @return requested contexts + @rtype list of DocStyleContext """ if kind == "moduleDocstring": return [DocStyleContext(self.__source, 0, "module")] @@ -674,8 +719,10 @@ """ Private method to check, if the module has a docstring. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: self.__error(context.start(), 0, "D101") @@ -697,8 +744,10 @@ Private method to check, that all public functions and methods have a docstring. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ functionName = context.source()[0].lstrip().split()[1].split("(")[0] if functionName.startswith("_") and not functionName.endswith("__"): @@ -731,8 +780,10 @@ Private method to check, that all public functions and methods have a docstring. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ className = context.source()[0].lstrip().split()[1].split("(")[0] if className.startswith("_"): @@ -764,8 +815,10 @@ Private method to check, that all docstrings are surrounded by triple double quotes. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -779,8 +832,10 @@ Private method to check, that all docstrings containing backslashes are surrounded by raw triple double quotes. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -794,8 +849,10 @@ Private method to check, that one-liner docstrings fit on one line with quotes. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -819,8 +876,10 @@ """ Private method to check, that docstrings are properly indented. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -844,8 +903,10 @@ """ Private method to check, that docstring summaries contain some text. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -858,8 +919,10 @@ """ Private method to check, that docstring summaries end with a period. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -873,8 +936,10 @@ Private method to check, that docstring summaries are in imperative mood. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -890,8 +955,10 @@ Private method to check, that docstring summaries don't repeat the function's signature. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -908,8 +975,10 @@ """ Private method to check, that docstrings mention the return value type. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -934,8 +1003,10 @@ Private method to check, that function/method docstrings are not preceded by a blank line. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -957,8 +1028,10 @@ Private method to check, that class docstrings have one blank line around them. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -995,8 +1068,10 @@ Private method to check, that docstring summaries are followed by a blank line. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -1015,8 +1090,10 @@ Private method to check, that the last paragraph of docstrings is followed by a blank line. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -1038,8 +1115,10 @@ Private method to check, that leading and trailing quotes are on a line by themselves. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -1054,8 +1133,10 @@ """ Private method to check, that docstring summaries end with a period. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -1081,8 +1162,10 @@ Private method to check, that docstrings contain an @return line if they return anything and don't otherwise. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -1109,8 +1192,10 @@ Private method to check, that docstrings contain an @yield line if they return anything and don't otherwise. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -1131,8 +1216,10 @@ Private method to check, that docstrings contain an @param and/or @keyparam line for each argument. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -1153,12 +1240,16 @@ if "cls" in argNames: argNames.remove("cls") - docstring = docstringContext.ssource() - if docstring.count("@param") + docstring.count("@keyparam") < len( + tagstring = "".join( + line.lstrip() + for line in docstringContext.source() + if line.lstrip().startswith("@") + ) + if tagstring.count("@param") + tagstring.count("@keyparam") < len( argNames + kwNames ): self.__error(docstringContext.end(), 0, "D236") - elif docstring.count("@param") + docstring.count("@keyparam") > len( + elif tagstring.count("@param") + tagstring.count("@keyparam") > len( argNames + kwNames ): self.__error(docstringContext.end(), 0, "D237") @@ -1192,8 +1283,10 @@ completeness (i.e. raised exceptions that are not documented or documented exceptions that are not raised) - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -1252,8 +1345,10 @@ completeness (i.e. defined signals that are not documented or documented signals that are not defined) - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -1300,8 +1395,10 @@ Private method to check, that docstring summaries are followed by a blank line. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -1325,8 +1422,10 @@ Private method to check, that class and function/method docstrings have no blank line around them. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -1381,8 +1480,10 @@ Private method to check, that the last paragraph of docstrings is not followed by a blank line. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -1400,8 +1501,10 @@ Private method to check, that method docstring summaries start with specific words. - @param docstringContext docstring context (DocStyleContext) - @param context context of the docstring (DocStyleContext) + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext """ if docstringContext is None: return @@ -1504,3 +1607,84 @@ self.__error( docstringContext.start() + lineNumber, 0, "D232", "public" ) + + def __checkEricDocumentationSequence( + self, + docstringContext, + context, # noqa: U100 + ): + """ + Private method to check, that method docstring follows the correct sequence + of entries (e.g. @param is followed by @type). + + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext + """ + if docstringContext is None: + return + + docTokens = [] + for lineno, line in enumerate(docstringContext.source()): + strippedLine = line.lstrip() + if strippedLine.startswith("@"): + docTokens.append((strippedLine.split(None, 1)[0], lineno)) + + for index in range(len(docTokens)): + docToken, lineno = docTokens[index] + try: + docToken2, _ = docTokens[index + 1] + except IndexError: + docToken2 = "" + + if docToken in ("@param", "@keyparam") and docToken2 != "@type": + self.__error( + docstringContext.start() + lineno, 0, "D270", docToken, "@type" + ) + elif docToken == "@return" and docToken2 != "@rtype": + self.__error( + docstringContext.start() + lineno, 0, "D270", docToken, "@rtype" + ) + elif docToken == "@yield" and docToken2 != "@ytype": + self.__error( + docstringContext.start() + lineno, 0, "D270", docToken, "@ytype" + ) + + def __checkEricDocumentationDeprecatedTags( + self, + docstringContext, + context, # noqa: U100 + ): + """ + Private method to check the use of deprecated documentation tags. + + @param docstringContext docstring context + @type DocStyleContext + @param context context of the docstring + @type DocStyleContext + """ + if docstringContext is None: + return + + deprecationsList = { + # key is deprecated tag, value is the tag to be used + "@ireturn": "@return", + "@ptype": "@type", + "@raise": "@exception", + "@throws": "@exception", + } + + for lineno, line in enumerate(docstringContext.source()): + strippedLine = line.lstrip() + if strippedLine.startswith("@"): + # it is a tag line + tag = strippedLine.split(None, 1)[0] + with contextlib.suppress(KeyError): + self.__error( + docstringContext.start() + lineno, + 0, + "D271", + tag, + deprecationsList[tag], + )