110 "D131", "D132", "D133", "D134", |
111 "D131", "D132", "D133", "D134", |
111 "D141", "D142", "D143", "D144", "D145", |
112 "D141", "D142", "D143", "D144", "D145", |
112 |
113 |
113 "D203", "D205", |
114 "D203", "D205", |
114 "D221", |
115 "D221", |
115 "D231", "D234", "D235", "D236", "D237", |
116 "D231", "D234", "D235", "D236", "D237", "D238", |
116 "D242", "D243", "D244", "D245", |
117 "D242", "D243", "D244", "D245", |
117 ] |
118 ] |
118 |
119 |
119 Messages = { |
120 Messages = { |
120 "D101": QT_TRANSLATE_NOOP( |
121 "D101": QT_TRANSLATE_NOOP( |
182 "docstring does not contain enough @param/@keyparam lines"), |
183 "docstring does not contain enough @param/@keyparam lines"), |
183 "D236": QT_TRANSLATE_NOOP( |
184 "D236": QT_TRANSLATE_NOOP( |
184 "Pep257Checker", |
185 "Pep257Checker", |
185 "docstring contains too many @param/@keyparam lines"), |
186 "docstring contains too many @param/@keyparam lines"), |
186 "D237": QT_TRANSLATE_NOOP( |
187 "D237": QT_TRANSLATE_NOOP( |
|
188 "Pep257Checker", |
|
189 "keyword only arguments must be documented with @keyparam lines"), |
|
190 "D238": QT_TRANSLATE_NOOP( |
187 "Pep257Checker", "order of @param/@keyparam lines does" |
191 "Pep257Checker", "order of @param/@keyparam lines does" |
188 " not match the function/method signature"), |
192 " not match the function/method signature"), |
189 "D242": QT_TRANSLATE_NOOP( |
193 "D242": QT_TRANSLATE_NOOP( |
190 "Pep257Checker", "class docstring is preceded by a blank line"), |
194 "Pep257Checker", "class docstring is preceded by a blank line"), |
191 "D243": QT_TRANSLATE_NOOP( |
195 "D243": QT_TRANSLATE_NOOP( |
293 (self.__checkFunctionDocstring, ("D102", "D203")), |
297 (self.__checkFunctionDocstring, ("D102", "D203")), |
294 (self.__checkImperativeMood, ("D132",)), |
298 (self.__checkImperativeMood, ("D132",)), |
295 (self.__checkNoSignature, ("D133",)), |
299 (self.__checkNoSignature, ("D133",)), |
296 (self.__checkEricReturn, ("D234",)), |
300 (self.__checkEricReturn, ("D234",)), |
297 (self.__checkEricFunctionArguments, |
301 (self.__checkEricFunctionArguments, |
298 ("D235", "D236", "D237")), |
302 ("D235", "D236", "D237", "D238")), |
299 (self.__checkNoBlankLineBefore, ("D141",)), |
303 (self.__checkNoBlankLineBefore, ("D141",)), |
300 ], |
304 ], |
301 "docstring": [ |
305 "docstring": [ |
302 (self.__checkTripleDoubleQuotes, ("D111",)), |
306 (self.__checkTripleDoubleQuotes, ("D111",)), |
303 (self.__checkBackslashes, ("D112",)), |
307 (self.__checkBackslashes, ("D112",)), |
357 text = code + " " + QCoreApplication.translate("Pep257Checker", |
361 text = code + " " + QCoreApplication.translate("Pep257Checker", |
358 "no message for this code defined") |
362 "no message for this code defined") |
359 # record the issue with one based line number |
363 # record the issue with one based line number |
360 self.errors.append((self.__filename, lineNumber + 1, offset, text)) |
364 self.errors.append((self.__filename, lineNumber + 1, offset, text)) |
361 |
365 |
362 def getMessage(self, code, *args): |
366 @classmethod |
363 """ |
367 def getMessage(cls, code, *args): |
364 Public method to get a translated and formatted message for a |
368 """ |
|
369 Class method to get a translated and formatted message for a |
365 given code. |
370 given code. |
366 |
371 |
367 @param code message code (string) |
372 @param code message code (string) |
368 @param args arguments for a formatted message (list) |
373 @param args arguments for a formatted message (list) |
369 @return translated and formatted message (string) |
374 @return translated and formatted message (string) |
472 else: |
477 else: |
473 lineno = 2 |
478 lineno = 2 |
474 summaries.append(line2) |
479 summaries.append(line2) |
475 return summaries, lineno |
480 return summaries, lineno |
476 |
481 |
477 def __getArgNames(self, node): |
482 if sys.version_info[0] < 3: |
478 """ |
483 def __getArgNames(self, node): |
479 Private method to get the argument names of a function node. |
484 """ |
480 |
485 Private method to get the argument names of a function node. |
481 @param node AST node to extract arguments names from |
486 |
482 @return list of argument names (list of string) |
487 @param node AST node to extract arguments names from |
483 """ |
488 @return tuple of two list of argument names, one for arguments |
484 arguments = [] |
489 and one for keyword arguments (tuple of list of string) |
485 arguments.extend([arg.arg for arg in node.args.args]) |
490 """ |
486 if node.args.vararg is not None: |
491 def unpackArgs(args): |
487 arguments.append(node.args.vararg) |
492 """ |
488 arguments.extend([arg.arg for arg in node.args.kwonlyargs]) |
493 Local helper function to unpack function argument names. |
489 if node.args.kwarg is not None: |
494 |
490 arguments.append(node.args.kwarg) |
495 @param args list of AST node arguments |
491 return arguments |
496 @return list of argument names (list of string) |
|
497 """ |
|
498 ret = [] |
|
499 for arg in args: |
|
500 if isinstance(arg, ast.Tuple): |
|
501 ret.extend(unpackArgs(arg.elts)) |
|
502 else: |
|
503 ret.append(arg.id) |
|
504 return ret |
|
505 |
|
506 arguments = unpackArgs(node.args.args) |
|
507 if node.args.vararg is not None: |
|
508 arguments.append(node.args.vararg) |
|
509 kwarguments = [] |
|
510 if node.args.kwarg is not None: |
|
511 kwarguments.append(node.args.kwarg) |
|
512 return arguments, kwarguments |
|
513 else: |
|
514 def __getArgNames(self, node): # __IGNORE_WARNING__ |
|
515 """ |
|
516 Private method to get the argument names of a function node. |
|
517 |
|
518 @param node AST node to extract arguments names from |
|
519 @return tuple of two list of argument names, one for arguments |
|
520 and one for keyword arguments (tuple of list of string) |
|
521 """ |
|
522 arguments = [] |
|
523 arguments.extend([arg.arg for arg in node.args.args]) |
|
524 if node.args.vararg is not None: |
|
525 arguments.append(node.args.vararg) |
|
526 |
|
527 kwarguments = [] |
|
528 kwarguments.extend([arg.arg for arg in node.args.kwonlyargs]) |
|
529 if node.args.kwarg is not None: |
|
530 kwarguments.append(node.args.kwarg) |
|
531 return arguments, kwarguments |
492 |
532 |
493 ################################################################## |
533 ################################################################## |
494 ## Parsing functionality below |
534 ## Parsing functionality below |
495 ################################################################## |
535 ################################################################## |
496 |
536 |
1082 except (SyntaxError, TypeError): |
1122 except (SyntaxError, TypeError): |
1083 return |
1123 return |
1084 if (isinstance(tree, ast.Module) and len(tree.body) == 1 and |
1124 if (isinstance(tree, ast.Module) and len(tree.body) == 1 and |
1085 isinstance(tree.body[0], ast.FunctionDef)): |
1125 isinstance(tree.body[0], ast.FunctionDef)): |
1086 functionDef = tree.body[0] |
1126 functionDef = tree.body[0] |
1087 argNames = self.__getArgNames(functionDef) |
1127 argNames, kwNames = self.__getArgNames(functionDef) |
1088 if "self" in argNames: |
1128 if "self" in argNames: |
1089 argNames.remove("self") |
1129 argNames.remove("self") |
1090 if "cls" in argNames: |
1130 if "cls" in argNames: |
1091 argNames.remove("cls") |
1131 argNames.remove("cls") |
1092 |
1132 |
1093 docstring = docstringContext.ssource() |
1133 docstring = docstringContext.ssource() |
1094 if (docstring.count("@param") + docstring.count("@keyparam") < |
1134 if (docstring.count("@param") + docstring.count("@keyparam") < |
1095 len(argNames)): |
1135 len(argNames + kwNames)): |
1096 self.__error(docstringContext.end(), 0, "D235") |
1136 self.__error(docstringContext.end(), 0, "D235") |
1097 elif (docstring.count("@param") + docstring.count("@keyparam") > |
1137 elif (docstring.count("@param") + docstring.count("@keyparam") > |
1098 len(argNames)): |
1138 len(argNames + kwNames)): |
1099 self.__error(docstringContext.end(), 0, "D236") |
1139 self.__error(docstringContext.end(), 0, "D236") |
1100 # TODO: check order (args, vararg, kwonlyargs, kwarg |
1140 else: |
|
1141 # extract @param and @keyparam from docstring |
|
1142 args = [] |
|
1143 kwargs = [] |
|
1144 for line in docstringContext.source(): |
|
1145 if line.strip().startswith(("@param", "@keyparam")): |
|
1146 at, name, _ = line.strip().split(None, 2) |
|
1147 if at == "@keyparam": |
|
1148 kwargs.append(name) |
|
1149 args.append(name) |
|
1150 |
|
1151 # do the checks |
|
1152 for name in kwNames: |
|
1153 if name not in kwargs: |
|
1154 self.__error(docstringContext.end(), 0, "D237") |
|
1155 return |
|
1156 if argNames + kwNames != args: |
|
1157 self.__error(docstringContext.end(), 0, "D238") |
1101 |
1158 |
1102 def __checkEricBlankAfterSummary(self, docstringContext, context): |
1159 def __checkEricBlankAfterSummary(self, docstringContext, context): |
1103 """ |
1160 """ |
1104 Private method to check, that docstring summaries are followed |
1161 Private method to check, that docstring summaries are followed |
1105 by a blank line. |
1162 by a blank line. |