214 elif self.__docType in ("eric", "eric_black"): |
263 elif self.__docType in ("eric", "eric_black"): |
215 checkersWithCodes = { |
264 checkersWithCodes = { |
216 "moduleDocstring": [ |
265 "moduleDocstring": [ |
217 (self.__checkModulesDocstrings, ("D101", "D201")), |
266 (self.__checkModulesDocstrings, ("D101", "D201")), |
218 ], |
267 ], |
219 "functionDocstring": [ |
268 "functionDocstring": [], |
220 ], |
|
221 "classDocstring": [ |
269 "classDocstring": [ |
222 (self.__checkClassDocstring, ("D104", "D205", "D206")), |
270 (self.__checkClassDocstring, ("D104", "D205", "D206")), |
223 (self.__checkEricNoBlankBeforeAndAfterClassOrFunction, |
271 ( |
224 ("D242", "D243")), |
272 self.__checkEricNoBlankBeforeAndAfterClassOrFunction, |
|
273 ("D242", "D243"), |
|
274 ), |
225 (self.__checkEricSignal, ("D260", "D261", "D262", "D263")), |
275 (self.__checkEricSignal, ("D260", "D261", "D262", "D263")), |
226 ], |
276 ], |
227 "methodDocstring": [ |
277 "methodDocstring": [ |
228 (self.__checkEricSummary, ("D232")), |
278 (self.__checkEricSummary, ("D232")), |
229 ], |
279 ], |
230 "defDocstring": [ |
280 "defDocstring": [ |
231 (self.__checkFunctionDocstring, |
281 ( |
232 ("D102", "D202.1", "D202.2", "D203")), |
282 self.__checkFunctionDocstring, |
|
283 ("D102", "D202.1", "D202.2", "D203"), |
|
284 ), |
233 (self.__checkImperativeMood, ("D132",)), |
285 (self.__checkImperativeMood, ("D132",)), |
234 (self.__checkNoSignature, ("D133",)), |
286 (self.__checkNoSignature, ("D133",)), |
235 (self.__checkEricReturn, ("D234r", "D235r")), |
287 (self.__checkEricReturn, ("D234r", "D235r")), |
236 (self.__checkEricYield, ("D234y", "D235y")), |
288 (self.__checkEricYield, ("D234y", "D235y")), |
237 (self.__checkEricFunctionArguments, |
289 ( |
238 ("D236", "D237", "D238", "D239")), |
290 self.__checkEricFunctionArguments, |
239 (self.__checkEricNoBlankBeforeAndAfterClassOrFunction, |
291 ("D236", "D237", "D238", "D239"), |
240 ("D244", "D245")), |
292 ), |
241 (self.__checkEricException, |
293 ( |
242 ("D250", "D251", "D252", "D253")), |
294 self.__checkEricNoBlankBeforeAndAfterClassOrFunction, |
|
295 ("D244", "D245"), |
|
296 ), |
|
297 (self.__checkEricException, ("D250", "D251", "D252", "D253")), |
243 ], |
298 ], |
244 "docstring": [ |
299 "docstring": [ |
245 (self.__checkTripleDoubleQuotes, ("D111",)), |
300 (self.__checkTripleDoubleQuotes, ("D111",)), |
246 (self.__checkBackslashes, ("D112",)), |
301 (self.__checkBackslashes, ("D112",)), |
247 (self.__checkIndent, ("D122",)), |
302 (self.__checkIndent, ("D122",)), |
248 (self.__checkSummary, ("D130",)), |
303 (self.__checkSummary, ("D130",)), |
249 (self.__checkEricEndsWithPeriod, ("D231",)), |
304 (self.__checkEricEndsWithPeriod, ("D231",)), |
250 (self.__checkEricBlankAfterSummary, ("D246",)), |
305 (self.__checkEricBlankAfterSummary, ("D246",)), |
251 (self.__checkEricNBlankAfterLastParagraph, ("D247",)), |
306 (self.__checkEricNBlankAfterLastParagraph, ("D247",)), |
252 (self.__checkEricQuotesOnSeparateLines, ("D222", "D223")) |
307 (self.__checkEricQuotesOnSeparateLines, ("D222", "D223")), |
253 ], |
308 ], |
254 } |
309 } |
255 |
310 |
256 self.__checkers = {} |
311 self.__checkers = {} |
257 for key, checkers in checkersWithCodes.items(): |
312 for key, checkers in checkersWithCodes.items(): |
258 for checker, codes in checkers: |
313 for checker, codes in checkers: |
259 if any(not (code and self.__ignoreCode(code)) |
314 if any(not (code and self.__ignoreCode(code)) for code in codes): |
260 for code in codes): |
|
261 if key not in self.__checkers: |
315 if key not in self.__checkers: |
262 self.__checkers[key] = [] |
316 self.__checkers[key] = [] |
263 self.__checkers[key].append(checker) |
317 self.__checkers[key].append(checker) |
264 |
318 |
265 def __ignoreCode(self, code): |
319 def __ignoreCode(self, code): |
266 """ |
320 """ |
267 Private method to check if the error code should be ignored. |
321 Private method to check if the error code should be ignored. |
268 |
322 |
269 @param code message code to check for (string) |
323 @param code message code to check for (string) |
270 @return flag indicating to ignore the given code (boolean) |
324 @return flag indicating to ignore the given code (boolean) |
271 """ |
325 """ |
272 return (code.startswith(self.__ignore) and |
326 return code.startswith(self.__ignore) and not code.startswith(self.__select) |
273 not code.startswith(self.__select)) |
327 |
274 |
|
275 def __error(self, lineNumber, offset, code, *args): |
328 def __error(self, lineNumber, offset, code, *args): |
276 """ |
329 """ |
277 Private method to record an issue. |
330 Private method to record an issue. |
278 |
331 |
279 @param lineNumber line number of the issue (integer) |
332 @param lineNumber line number of the issue (integer) |
280 @param offset position within line of the issue (integer) |
333 @param offset position within line of the issue (integer) |
281 @param code message code (string) |
334 @param code message code (string) |
282 @param args arguments for the message (list) |
335 @param args arguments for the message (list) |
283 """ |
336 """ |
284 if self.__ignoreCode(code): |
337 if self.__ignoreCode(code): |
285 return |
338 return |
286 |
339 |
287 if code in self.counters: |
340 if code in self.counters: |
288 self.counters[code] += 1 |
341 self.counters[code] += 1 |
289 else: |
342 else: |
290 self.counters[code] = 1 |
343 self.counters[code] = 1 |
291 |
344 |
292 # Don't care about expected codes |
345 # Don't care about expected codes |
293 if code in self.__expected: |
346 if code in self.__expected: |
294 return |
347 return |
295 |
348 |
296 if code and (self.counters[code] == 1 or self.__repeat): |
349 if code and (self.counters[code] == 1 or self.__repeat): |
297 # record the issue with one based line number |
350 # record the issue with one based line number |
298 self.errors.append( |
351 self.errors.append( |
299 { |
352 { |
300 "file": self.__filename, |
353 "file": self.__filename, |
407 summaries.append(line2) |
464 summaries.append(line2) |
408 else: |
465 else: |
409 lineno = 2 |
466 lineno = 2 |
410 summaries.append(line2) |
467 summaries.append(line2) |
411 return summaries, lineno |
468 return summaries, lineno |
412 |
469 |
413 def __getArgNames(self, node): |
470 def __getArgNames(self, node): |
414 """ |
471 """ |
415 Private method to get the argument names of a function node. |
472 Private method to get the argument names of a function node. |
416 |
473 |
417 @param node AST node to extract arguments names from |
474 @param node AST node to extract arguments names from |
418 @return tuple of two list of argument names, one for arguments |
475 @return tuple of two list of argument names, one for arguments |
419 and one for keyword arguments (tuple of list of string) |
476 and one for keyword arguments (tuple of list of string) |
420 """ |
477 """ |
421 arguments = [] |
478 arguments = [] |
422 arguments.extend([arg.arg for arg in node.args.args]) |
479 arguments.extend([arg.arg for arg in node.args.args]) |
423 if node.args.vararg is not None: |
480 if node.args.vararg is not None: |
424 arguments.append(node.args.vararg.arg) |
481 arguments.append(node.args.vararg.arg) |
425 |
482 |
426 kwarguments = [] |
483 kwarguments = [] |
427 kwarguments.extend([arg.arg for arg in node.args.kwonlyargs]) |
484 kwarguments.extend([arg.arg for arg in node.args.kwonlyargs]) |
428 if node.args.kwarg is not None: |
485 if node.args.kwarg is not None: |
429 kwarguments.append(node.args.kwarg.arg) |
486 kwarguments.append(node.args.kwarg.arg) |
430 return arguments, kwarguments |
487 return arguments, kwarguments |
431 |
488 |
432 ################################################################## |
489 ################################################################## |
433 ## Parsing functionality below |
490 ## Parsing functionality below |
434 ################################################################## |
491 ################################################################## |
435 |
492 |
436 def __parseModuleDocstring(self, source): |
493 def __parseModuleDocstring(self, source): |
437 """ |
494 """ |
438 Private method to extract a docstring given a module source. |
495 Private method to extract a docstring given a module source. |
439 |
496 |
440 @param source source to parse (list of string) |
497 @param source source to parse (list of string) |
441 @return context of extracted docstring (DocStyleContext) |
498 @return context of extracted docstring (DocStyleContext) |
442 """ |
499 """ |
443 for kind, value, (line, _char), _, _ in tokenize.generate_tokens( |
500 for kind, value, (line, _char), _, _ in tokenize.generate_tokens( |
444 StringIO("".join(source)).readline): |
501 StringIO("".join(source)).readline |
|
502 ): |
445 if kind in [tokenize.COMMENT, tokenize.NEWLINE, tokenize.NL]: |
503 if kind in [tokenize.COMMENT, tokenize.NEWLINE, tokenize.NL]: |
446 continue |
504 continue |
447 elif kind == tokenize.STRING: # first STRING should be docstring |
505 elif kind == tokenize.STRING: # first STRING should be docstring |
448 return DocStyleContext(value, line - 1, "docstring") |
506 return DocStyleContext(value, line - 1, "docstring") |
449 else: |
507 else: |
450 return None |
508 return None |
451 |
509 |
452 return None |
510 return None |
453 |
511 |
454 def __parseDocstring(self, context, what=''): |
512 def __parseDocstring(self, context, what=""): |
455 """ |
513 """ |
456 Private method to extract a docstring given `def` or `class` source. |
514 Private method to extract a docstring given `def` or `class` source. |
457 |
515 |
458 @param context context data to get the docstring from (DocStyleContext) |
516 @param context context data to get the docstring from (DocStyleContext) |
459 @param what string denoting what is being parsed (string) |
517 @param what string denoting what is being parsed (string) |
460 @return context of extracted docstring (DocStyleContext) |
518 @return context of extracted docstring (DocStyleContext) |
461 """ |
519 """ |
462 moduleDocstring = self.__parseModuleDocstring(context.source()) |
520 moduleDocstring = self.__parseModuleDocstring(context.source()) |
463 if what.startswith('module') or context.contextType() == "module": |
521 if what.startswith("module") or context.contextType() == "module": |
464 return moduleDocstring |
522 return moduleDocstring |
465 if moduleDocstring: |
523 if moduleDocstring: |
466 return moduleDocstring |
524 return moduleDocstring |
467 |
525 |
468 tokenGenerator = tokenize.generate_tokens( |
526 tokenGenerator = tokenize.generate_tokens(StringIO(context.ssource()).readline) |
469 StringIO(context.ssource()).readline) |
|
470 with contextlib.suppress(StopIteration): |
527 with contextlib.suppress(StopIteration): |
471 kind = None |
528 kind = None |
472 while kind != tokenize.INDENT: |
529 while kind != tokenize.INDENT: |
473 kind, _, _, _, _ = next(tokenGenerator) |
530 kind, _, _, _, _ = next(tokenGenerator) |
474 kind, value, (line, char), _, _ = next(tokenGenerator) |
531 kind, value, (line, char), _, _ = next(tokenGenerator) |
475 if kind == tokenize.STRING: # STRING after INDENT is a docstring |
532 if kind == tokenize.STRING: # STRING after INDENT is a docstring |
476 return DocStyleContext( |
533 return DocStyleContext(value, context.start() + line - 1, "docstring") |
477 value, context.start() + line - 1, "docstring") |
534 |
478 |
|
479 return None |
535 return None |
480 |
536 |
481 def __parseTopLevel(self, keyword): |
537 def __parseTopLevel(self, keyword): |
482 """ |
538 """ |
483 Private method to extract top-level functions or classes. |
539 Private method to extract top-level functions or classes. |
484 |
540 |
485 @param keyword keyword signaling what to extract (string) |
541 @param keyword keyword signaling what to extract (string) |
486 @return extracted function or class contexts (list of DocStyleContext) |
542 @return extracted function or class contexts (list of DocStyleContext) |
487 """ |
543 """ |
488 self.__resetReadline() |
544 self.__resetReadline() |
489 tokenGenerator = tokenize.generate_tokens(self.__readline) |
545 tokenGenerator = tokenize.generate_tokens(self.__readline) |
490 kind, value, char = None, None, None |
546 kind, value, char = None, None, None |
491 contexts = [] |
547 contexts = [] |
492 try: |
548 try: |
493 while True: |
549 while True: |
494 start, end = None, None |
550 start, end = None, None |
495 while not (kind == tokenize.NAME and |
551 while not (kind == tokenize.NAME and value == keyword and char == 0): |
496 value == keyword and |
|
497 char == 0): |
|
498 kind, value, (line, char), _, _ = next(tokenGenerator) |
552 kind, value, (line, char), _, _ = next(tokenGenerator) |
499 start = line - 1, char |
553 start = line - 1, char |
500 while not (kind == tokenize.DEDENT and |
554 while not (kind == tokenize.DEDENT and value == "" and char == 0): |
501 value == '' and |
|
502 char == 0): |
|
503 kind, value, (line, char), _, _ = next(tokenGenerator) |
555 kind, value, (line, char), _, _ = next(tokenGenerator) |
504 end = line - 1, char |
556 end = line - 1, char |
505 contexts.append(DocStyleContext( |
557 contexts.append( |
506 self.__source[start[0]:end[0]], start[0], keyword)) |
558 DocStyleContext(self.__source[start[0] : end[0]], start[0], keyword) |
|
559 ) |
507 except StopIteration: |
560 except StopIteration: |
508 return contexts |
561 return contexts |
509 |
562 |
510 def __parseFunctions(self): |
563 def __parseFunctions(self): |
511 """ |
564 """ |
512 Private method to extract top-level functions. |
565 Private method to extract top-level functions. |
513 |
566 |
514 @return extracted function contexts (list of DocStyleContext) |
567 @return extracted function contexts (list of DocStyleContext) |
515 """ |
568 """ |
516 if not self.__functionsCache: |
569 if not self.__functionsCache: |
517 self.__functionsCache = self.__parseTopLevel('def') |
570 self.__functionsCache = self.__parseTopLevel("def") |
518 return self.__functionsCache |
571 return self.__functionsCache |
519 |
572 |
520 def __parseClasses(self): |
573 def __parseClasses(self): |
521 """ |
574 """ |
522 Private method to extract top-level classes. |
575 Private method to extract top-level classes. |
523 |
576 |
524 @return extracted class contexts (list of DocStyleContext) |
577 @return extracted class contexts (list of DocStyleContext) |
525 """ |
578 """ |
526 if not self.__classesCache: |
579 if not self.__classesCache: |
527 self.__classesCache = self.__parseTopLevel('class') |
580 self.__classesCache = self.__parseTopLevel("class") |
528 return self.__classesCache |
581 return self.__classesCache |
529 |
582 |
530 def __skipIndentedBlock(self, tokenGenerator): |
583 def __skipIndentedBlock(self, tokenGenerator): |
531 """ |
584 """ |
532 Private method to skip over an indented block of source code. |
585 Private method to skip over an indented block of source code. |
533 |
586 |
534 @param tokenGenerator token generator |
587 @param tokenGenerator token generator |
535 @return last token of the indented block |
588 @return last token of the indented block |
536 """ |
589 """ |
537 kind, value, start, end, raw = next(tokenGenerator) |
590 kind, value, start, end, raw = next(tokenGenerator) |
538 while kind != tokenize.INDENT: |
591 while kind != tokenize.INDENT: |
543 indent += 1 |
596 indent += 1 |
544 elif kind == tokenize.DEDENT: |
597 elif kind == tokenize.DEDENT: |
545 indent -= 1 |
598 indent -= 1 |
546 if indent == 0: |
599 if indent == 0: |
547 return kind, value, start, end, raw |
600 return kind, value, start, end, raw |
548 |
601 |
549 return None |
602 return None |
550 |
603 |
551 def __parseMethods(self): |
604 def __parseMethods(self): |
552 """ |
605 """ |
553 Private method to extract methods of all classes. |
606 Private method to extract methods of all classes. |
554 |
607 |
555 @return extracted method contexts (list of DocStyleContext) |
608 @return extracted method contexts (list of DocStyleContext) |
556 """ |
609 """ |
557 if not self.__methodsCache: |
610 if not self.__methodsCache: |
558 contexts = [] |
611 contexts = [] |
559 for classContext in self.__parseClasses(): |
612 for classContext in self.__parseClasses(): |
560 tokenGenerator = tokenize.generate_tokens( |
613 tokenGenerator = tokenize.generate_tokens( |
561 StringIO(classContext.ssource()).readline) |
614 StringIO(classContext.ssource()).readline |
|
615 ) |
562 kind, value, char = None, None, None |
616 kind, value, char = None, None, None |
563 with contextlib.suppress(StopIteration): |
617 with contextlib.suppress(StopIteration): |
564 while True: |
618 while True: |
565 start, end = None, None |
619 start, end = None, None |
566 while not (kind == tokenize.NAME and value == 'def'): |
620 while not (kind == tokenize.NAME and value == "def"): |
567 kind, value, (line, char), _, _ = ( |
621 kind, value, (line, char), _, _ = next(tokenGenerator) |
568 next(tokenGenerator) |
|
569 ) |
|
570 start = line - 1, char |
622 start = line - 1, char |
571 kind, value, (line, char), _, _ = ( |
623 kind, value, (line, char), _, _ = self.__skipIndentedBlock( |
572 self.__skipIndentedBlock(tokenGenerator) |
624 tokenGenerator |
573 ) |
625 ) |
574 end = line - 1, char |
626 end = line - 1, char |
575 startLine = classContext.start() + start[0] |
627 startLine = classContext.start() + start[0] |
576 endLine = classContext.start() + end[0] |
628 endLine = classContext.start() + end[0] |
577 context = DocStyleContext( |
629 context = DocStyleContext( |
578 self.__source[startLine:endLine], |
630 self.__source[startLine:endLine], startLine, "def" |
579 startLine, "def") |
631 ) |
580 if startLine > 0: |
632 if startLine > 0: |
581 if ( |
633 if self.__source[startLine - 1].strip() == "@staticmethod": |
582 self.__source[startLine - 1].strip() == |
|
583 "@staticmethod" |
|
584 ): |
|
585 context.setSpecial("staticmethod") |
634 context.setSpecial("staticmethod") |
586 elif ( |
635 elif self.__source[startLine - 1].strip() == "@classmethod": |
587 self.__source[startLine - 1].strip() == |
|
588 "@classmethod" |
|
589 ): |
|
590 context.setSpecial("classmethod") |
636 context.setSpecial("classmethod") |
591 contexts.append(context) |
637 contexts.append(context) |
592 self.__methodsCache = contexts |
638 self.__methodsCache = contexts |
593 |
639 |
594 return self.__methodsCache |
640 return self.__methodsCache |
595 |
641 |
596 def __parseContexts(self, kind): |
642 def __parseContexts(self, kind): |
597 """ |
643 """ |
598 Private method to extract a context from the source. |
644 Private method to extract a context from the source. |
599 |
645 |
600 @param kind kind of context to extract (string) |
646 @param kind kind of context to extract (string) |
601 @return requested contexts (list of DocStyleContext) |
647 @return requested contexts (list of DocStyleContext) |
602 """ |
648 """ |
603 if kind == 'moduleDocstring': |
649 if kind == "moduleDocstring": |
604 return [DocStyleContext(self.__source, 0, "module")] |
650 return [DocStyleContext(self.__source, 0, "module")] |
605 if kind == 'functionDocstring': |
651 if kind == "functionDocstring": |
606 return self.__parseFunctions() |
652 return self.__parseFunctions() |
607 if kind == 'classDocstring': |
653 if kind == "classDocstring": |
608 return self.__parseClasses() |
654 return self.__parseClasses() |
609 if kind == 'methodDocstring': |
655 if kind == "methodDocstring": |
610 return self.__parseMethods() |
656 return self.__parseMethods() |
611 if kind == 'defDocstring': |
657 if kind == "defDocstring": |
612 return self.__parseFunctions() + self.__parseMethods() |
658 return self.__parseFunctions() + self.__parseMethods() |
613 if kind == 'docstring': |
659 if kind == "docstring": |
614 return ([DocStyleContext(self.__source, 0, "module")] + |
660 return ( |
615 self.__parseFunctions() + |
661 [DocStyleContext(self.__source, 0, "module")] |
616 self.__parseClasses() + |
662 + self.__parseFunctions() |
617 self.__parseMethods()) |
663 + self.__parseClasses() |
618 return [] # fall back |
664 + self.__parseMethods() |
619 |
665 ) |
|
666 return [] # fall back |
|
667 |
620 ################################################################## |
668 ################################################################## |
621 ## Checking functionality below (PEP-257) |
669 ## Checking functionality below (PEP-257) |
622 ################################################################## |
670 ################################################################## |
623 |
671 |
624 def __checkModulesDocstrings(self, docstringContext, context): |
672 def __checkModulesDocstrings(self, docstringContext, context): |
625 """ |
673 """ |
626 Private method to check, if the module has a docstring. |
674 Private method to check, if the module has a docstring. |
627 |
675 |
628 @param docstringContext docstring context (DocStyleContext) |
676 @param docstringContext docstring context (DocStyleContext) |
629 @param context context of the docstring (DocStyleContext) |
677 @param context context of the docstring (DocStyleContext) |
630 """ |
678 """ |
631 if docstringContext is None: |
679 if docstringContext is None: |
632 self.__error(context.start(), 0, "D101") |
680 self.__error(context.start(), 0, "D101") |
633 return |
681 return |
634 |
682 |
635 docstring = docstringContext.ssource() |
683 docstring = docstringContext.ssource() |
636 if (not docstring or not docstring.strip() or |
684 if not docstring or not docstring.strip() or not docstring.strip("'\""): |
637 not docstring.strip('\'"')): |
|
638 self.__error(context.start(), 0, "D101") |
685 self.__error(context.start(), 0, "D101") |
639 |
686 |
640 if ( |
687 if ( |
641 self.__docType == "eric" and |
688 self.__docType == "eric" |
642 docstring.strip('\'"').strip() == |
689 and docstring.strip("'\"").strip() == "Module documentation goes here." |
643 "Module documentation goes here." |
|
644 ): |
690 ): |
645 self.__error(docstringContext.end(), 0, "D201") |
691 self.__error(docstringContext.end(), 0, "D201") |
646 return |
692 return |
647 |
693 |
648 def __checkFunctionDocstring(self, docstringContext, context): |
694 def __checkFunctionDocstring(self, docstringContext, context): |
649 """ |
695 """ |
650 Private method to check, that all public functions and methods |
696 Private method to check, that all public functions and methods |
651 have a docstring. |
697 have a docstring. |
652 |
698 |
653 @param docstringContext docstring context (DocStyleContext) |
699 @param docstringContext docstring context (DocStyleContext) |
654 @param context context of the docstring (DocStyleContext) |
700 @param context context of the docstring (DocStyleContext) |
655 """ |
701 """ |
656 functionName = context.source()[0].lstrip().split()[1].split("(")[0] |
702 functionName = context.source()[0].lstrip().split()[1].split("(")[0] |
657 if functionName.startswith('_') and not functionName.endswith('__'): |
703 if functionName.startswith("_") and not functionName.endswith("__"): |
658 if self.__docType == "eric": |
704 if self.__docType == "eric": |
659 code = "D203" |
705 code = "D203" |
660 else: |
706 else: |
661 code = "D103" |
707 code = "D103" |
662 else: |
708 else: |
663 code = "D102" |
709 code = "D102" |
664 |
710 |
665 if docstringContext is None: |
711 if docstringContext is None: |
666 self.__error(context.start(), 0, code) |
712 self.__error(context.start(), 0, code) |
667 return |
713 return |
668 |
714 |
669 docstring = docstringContext.ssource() |
715 docstring = docstringContext.ssource() |
670 if (not docstring or not docstring.strip() or |
716 if not docstring or not docstring.strip() or not docstring.strip("'\""): |
671 not docstring.strip('\'"')): |
|
672 self.__error(context.start(), 0, code) |
717 self.__error(context.start(), 0, code) |
673 |
718 |
674 if self.__docType == "eric": |
719 if self.__docType == "eric": |
675 if ( |
720 if docstring.strip("'\"").strip() == "Function documentation goes here.": |
676 docstring.strip('\'"').strip() == |
|
677 "Function documentation goes here." |
|
678 ): |
|
679 self.__error(docstringContext.end(), 0, "D202.1") |
721 self.__error(docstringContext.end(), 0, "D202.1") |
680 return |
722 return |
681 |
723 |
682 if ( |
724 if "DESCRIPTION" in docstring or "TYPE" in docstring: |
683 "DESCRIPTION" in docstring or |
|
684 "TYPE" in docstring |
|
685 ): |
|
686 self.__error(docstringContext.end(), 0, "D202.2") |
725 self.__error(docstringContext.end(), 0, "D202.2") |
687 return |
726 return |
688 |
727 |
689 def __checkClassDocstring(self, docstringContext, context): |
728 def __checkClassDocstring(self, docstringContext, context): |
690 """ |
729 """ |
691 Private method to check, that all public functions and methods |
730 Private method to check, that all public functions and methods |
692 have a docstring. |
731 have a docstring. |
693 |
732 |
694 @param docstringContext docstring context (DocStyleContext) |
733 @param docstringContext docstring context (DocStyleContext) |
695 @param context context of the docstring (DocStyleContext) |
734 @param context context of the docstring (DocStyleContext) |
696 """ |
735 """ |
697 className = context.source()[0].lstrip().split()[1].split("(")[0] |
736 className = context.source()[0].lstrip().split()[1].split("(")[0] |
698 if className.startswith('_'): |
737 if className.startswith("_"): |
699 if self.__docType == "eric": |
738 if self.__docType == "eric": |
700 code = "D205" |
739 code = "D205" |
701 else: |
740 else: |
702 code = "D105" |
741 code = "D105" |
703 else: |
742 else: |
704 code = "D104" |
743 code = "D104" |
705 |
744 |
706 if docstringContext is None: |
745 if docstringContext is None: |
707 self.__error(context.start(), 0, code) |
746 self.__error(context.start(), 0, code) |
708 return |
747 return |
709 |
748 |
710 docstring = docstringContext.ssource() |
749 docstring = docstringContext.ssource() |
711 if (not docstring or not docstring.strip() or |
750 if not docstring or not docstring.strip() or not docstring.strip("'\""): |
712 not docstring.strip('\'"')): |
|
713 self.__error(context.start(), 0, code) |
751 self.__error(context.start(), 0, code) |
714 return |
752 return |
715 |
753 |
716 if ( |
754 if ( |
717 self.__docType == "eric" and |
755 self.__docType == "eric" |
718 docstring.strip('\'"').strip() == "Class documentation goes here." |
756 and docstring.strip("'\"").strip() == "Class documentation goes here." |
719 ): |
757 ): |
720 self.__error(docstringContext.end(), 0, "D206") |
758 self.__error(docstringContext.end(), 0, "D206") |
721 return |
759 return |
722 |
760 |
723 def __checkTripleDoubleQuotes(self, docstringContext, context): |
761 def __checkTripleDoubleQuotes(self, docstringContext, context): |
724 """ |
762 """ |
725 Private method to check, that all docstrings are surrounded |
763 Private method to check, that all docstrings are surrounded |
726 by triple double quotes. |
764 by triple double quotes. |
727 |
765 |
728 @param docstringContext docstring context (DocStyleContext) |
766 @param docstringContext docstring context (DocStyleContext) |
729 @param context context of the docstring (DocStyleContext) |
767 @param context context of the docstring (DocStyleContext) |
730 """ |
768 """ |
731 if docstringContext is None: |
769 if docstringContext is None: |
732 return |
770 return |
733 |
771 |
734 docstring = docstringContext.ssource().strip() |
772 docstring = docstringContext.ssource().strip() |
735 if not docstring.startswith(('"""', 'r"""', 'u"""')): |
773 if not docstring.startswith(('"""', 'r"""', 'u"""')): |
736 self.__error(docstringContext.start(), 0, "D111") |
774 self.__error(docstringContext.start(), 0, "D111") |
737 |
775 |
738 def __checkBackslashes(self, docstringContext, context): |
776 def __checkBackslashes(self, docstringContext, context): |
739 """ |
777 """ |
740 Private method to check, that all docstrings containing |
778 Private method to check, that all docstrings containing |
741 backslashes are surrounded by raw triple double quotes. |
779 backslashes are surrounded by raw triple double quotes. |
742 |
780 |
743 @param docstringContext docstring context (DocStyleContext) |
781 @param docstringContext docstring context (DocStyleContext) |
744 @param context context of the docstring (DocStyleContext) |
782 @param context context of the docstring (DocStyleContext) |
745 """ |
783 """ |
746 if docstringContext is None: |
784 if docstringContext is None: |
747 return |
785 return |
748 |
786 |
749 docstring = docstringContext.ssource().strip() |
787 docstring = docstringContext.ssource().strip() |
750 if "\\" in docstring and not docstring.startswith('r"""'): |
788 if "\\" in docstring and not docstring.startswith('r"""'): |
751 self.__error(docstringContext.start(), 0, "D112") |
789 self.__error(docstringContext.start(), 0, "D112") |
752 |
790 |
753 def __checkOneLiner(self, docstringContext, context): |
791 def __checkOneLiner(self, docstringContext, context): |
754 """ |
792 """ |
755 Private method to check, that one-liner docstrings fit on |
793 Private method to check, that one-liner docstrings fit on |
756 one line with quotes. |
794 one line with quotes. |
757 |
795 |
758 @param docstringContext docstring context (DocStyleContext) |
796 @param docstringContext docstring context (DocStyleContext) |
759 @param context context of the docstring (DocStyleContext) |
797 @param context context of the docstring (DocStyleContext) |
760 """ |
798 """ |
761 if docstringContext is None: |
799 if docstringContext is None: |
762 return |
800 return |
763 |
801 |
764 lines = docstringContext.source() |
802 lines = docstringContext.source() |
765 if len(lines) > 1: |
803 if len(lines) > 1: |
766 nonEmptyLines = [line for line in lines |
804 nonEmptyLines = [line for line in lines if line.strip().strip("'\"")] |
767 if line.strip().strip('\'"')] |
|
768 if len(nonEmptyLines) == 1: |
805 if len(nonEmptyLines) == 1: |
769 modLen = len(context.indent() + '"""' + |
806 modLen = len( |
770 nonEmptyLines[0].strip() + '"""') |
807 context.indent() + '"""' + nonEmptyLines[0].strip() + '"""' |
|
808 ) |
771 if context.contextType() != "module": |
809 if context.contextType() != "module": |
772 modLen += 4 |
810 modLen += 4 |
773 if not nonEmptyLines[0].strip().endswith("."): |
811 if not nonEmptyLines[0].strip().endswith("."): |
774 # account for a trailing dot |
812 # account for a trailing dot |
775 modLen += 1 |
813 modLen += 1 |
776 if modLen <= self.__maxLineLength: |
814 if modLen <= self.__maxLineLength: |
777 self.__error(docstringContext.start(), 0, "D121") |
815 self.__error(docstringContext.start(), 0, "D121") |
778 |
816 |
779 def __checkIndent(self, docstringContext, context): |
817 def __checkIndent(self, docstringContext, context): |
780 """ |
818 """ |
781 Private method to check, that docstrings are properly indented. |
819 Private method to check, that docstrings are properly indented. |
782 |
820 |
783 @param docstringContext docstring context (DocStyleContext) |
821 @param docstringContext docstring context (DocStyleContext) |
784 @param context context of the docstring (DocStyleContext) |
822 @param context context of the docstring (DocStyleContext) |
785 """ |
823 """ |
786 if docstringContext is None: |
824 if docstringContext is None: |
787 return |
825 return |
788 |
826 |
789 lines = docstringContext.source() |
827 lines = docstringContext.source() |
790 if len(lines) == 1: |
828 if len(lines) == 1: |
791 return |
829 return |
792 |
830 |
793 nonEmptyLines = [line.rstrip() for line in lines[1:] if line.strip()] |
831 nonEmptyLines = [line.rstrip() for line in lines[1:] if line.strip()] |
794 if not nonEmptyLines: |
832 if not nonEmptyLines: |
795 return |
833 return |
796 |
834 |
797 indent = min(len(line) - len(line.strip()) for line in nonEmptyLines) |
835 indent = min(len(line) - len(line.strip()) for line in nonEmptyLines) |
798 expectedIndent = ( |
836 expectedIndent = ( |
799 0 |
837 0 if context.contextType() == "module" else len(context.indent()) + 4 |
800 if context.contextType() == "module" else |
|
801 len(context.indent()) + 4 |
|
802 ) |
838 ) |
803 if indent != expectedIndent: |
839 if indent != expectedIndent: |
804 self.__error(docstringContext.start(), 0, "D122") |
840 self.__error(docstringContext.start(), 0, "D122") |
805 |
841 |
806 def __checkSummary(self, docstringContext, context): |
842 def __checkSummary(self, docstringContext, context): |
807 """ |
843 """ |
808 Private method to check, that docstring summaries contain some text. |
844 Private method to check, that docstring summaries contain some text. |
809 |
845 |
810 @param docstringContext docstring context (DocStyleContext) |
846 @param docstringContext docstring context (DocStyleContext) |
811 @param context context of the docstring (DocStyleContext) |
847 @param context context of the docstring (DocStyleContext) |
812 """ |
848 """ |
813 if docstringContext is None: |
849 if docstringContext is None: |
814 return |
850 return |
815 |
851 |
816 summary, lineNumber = self.__getSummaryLine(docstringContext) |
852 summary, lineNumber = self.__getSummaryLine(docstringContext) |
817 if summary == "": |
853 if summary == "": |
818 self.__error(docstringContext.start() + lineNumber, 0, "D130") |
854 self.__error(docstringContext.start() + lineNumber, 0, "D130") |
819 |
855 |
820 def __checkEndsWithPeriod(self, docstringContext, context): |
856 def __checkEndsWithPeriod(self, docstringContext, context): |
821 """ |
857 """ |
822 Private method to check, that docstring summaries end with a period. |
858 Private method to check, that docstring summaries end with a period. |
823 |
859 |
824 @param docstringContext docstring context (DocStyleContext) |
860 @param docstringContext docstring context (DocStyleContext) |
825 @param context context of the docstring (DocStyleContext) |
861 @param context context of the docstring (DocStyleContext) |
826 """ |
862 """ |
827 if docstringContext is None: |
863 if docstringContext is None: |
828 return |
864 return |
829 |
865 |
830 summary, lineNumber = self.__getSummaryLine(docstringContext) |
866 summary, lineNumber = self.__getSummaryLine(docstringContext) |
831 if not summary.endswith("."): |
867 if not summary.endswith("."): |
832 self.__error(docstringContext.start() + lineNumber, 0, "D131") |
868 self.__error(docstringContext.start() + lineNumber, 0, "D131") |
833 |
869 |
834 def __checkImperativeMood(self, docstringContext, context): |
870 def __checkImperativeMood(self, docstringContext, context): |
835 """ |
871 """ |
836 Private method to check, that docstring summaries are in |
872 Private method to check, that docstring summaries are in |
837 imperative mood. |
873 imperative mood. |
838 |
874 |
839 @param docstringContext docstring context (DocStyleContext) |
875 @param docstringContext docstring context (DocStyleContext) |
840 @param context context of the docstring (DocStyleContext) |
876 @param context context of the docstring (DocStyleContext) |
841 """ |
877 """ |
842 if docstringContext is None: |
878 if docstringContext is None: |
843 return |
879 return |
844 |
880 |
845 summary, lineNumber = self.__getSummaryLine(docstringContext) |
881 summary, lineNumber = self.__getSummaryLine(docstringContext) |
846 if summary: |
882 if summary: |
847 firstWord = summary.strip().split()[0] |
883 firstWord = summary.strip().split()[0] |
848 if firstWord.endswith("s") and not firstWord.endswith("ss"): |
884 if firstWord.endswith("s") and not firstWord.endswith("ss"): |
849 self.__error(docstringContext.start() + lineNumber, 0, "D132") |
885 self.__error(docstringContext.start() + lineNumber, 0, "D132") |
850 |
886 |
851 def __checkNoSignature(self, docstringContext, context): |
887 def __checkNoSignature(self, docstringContext, context): |
852 """ |
888 """ |
853 Private method to check, that docstring summaries don't repeat |
889 Private method to check, that docstring summaries don't repeat |
854 the function's signature. |
890 the function's signature. |
855 |
891 |
856 @param docstringContext docstring context (DocStyleContext) |
892 @param docstringContext docstring context (DocStyleContext) |
857 @param context context of the docstring (DocStyleContext) |
893 @param context context of the docstring (DocStyleContext) |
858 """ |
894 """ |
859 if docstringContext is None: |
895 if docstringContext is None: |
860 return |
896 return |
861 |
897 |
862 functionName = context.source()[0].lstrip().split()[1].split("(")[0] |
898 functionName = context.source()[0].lstrip().split()[1].split("(")[0] |
863 summary, lineNumber = self.__getSummaryLine(docstringContext) |
899 summary, lineNumber = self.__getSummaryLine(docstringContext) |
864 if ( |
900 if functionName + "(" in summary.replace( |
865 functionName + "(" in summary.replace(" ", "") and |
901 " ", "" |
866 functionName + "()" not in summary.replace(" ", "") |
902 ) and functionName + "()" not in summary.replace(" ", ""): |
867 ): |
|
868 # report only, if it is not an abbreviated form (i.e. function() ) |
903 # report only, if it is not an abbreviated form (i.e. function() ) |
869 self.__error(docstringContext.start() + lineNumber, 0, "D133") |
904 self.__error(docstringContext.start() + lineNumber, 0, "D133") |
870 |
905 |
871 def __checkReturnType(self, docstringContext, context): |
906 def __checkReturnType(self, docstringContext, context): |
872 """ |
907 """ |
873 Private method to check, that docstrings mention the return value type. |
908 Private method to check, that docstrings mention the return value type. |
874 |
909 |
875 @param docstringContext docstring context (DocStyleContext) |
910 @param docstringContext docstring context (DocStyleContext) |
876 @param context context of the docstring (DocStyleContext) |
911 @param context context of the docstring (DocStyleContext) |
877 """ |
912 """ |
878 if docstringContext is None: |
913 if docstringContext is None: |
879 return |
914 return |
880 |
915 |
881 if "return" not in docstringContext.ssource().lower(): |
916 if "return" not in docstringContext.ssource().lower(): |
882 tokens = list( |
917 tokens = list( |
883 tokenize.generate_tokens(StringIO(context.ssource()).readline)) |
918 tokenize.generate_tokens(StringIO(context.ssource()).readline) |
884 return_ = [tokens[i + 1][0] for i, token in enumerate(tokens) |
919 ) |
885 if token[1] == "return"] |
920 return_ = [ |
886 if (set(return_) - |
921 tokens[i + 1][0] |
887 {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} != |
922 for i, token in enumerate(tokens) |
888 set()): |
923 if token[1] == "return" |
|
924 ] |
|
925 if ( |
|
926 set(return_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} |
|
927 != set() |
|
928 ): |
889 self.__error(docstringContext.end(), 0, "D134") |
929 self.__error(docstringContext.end(), 0, "D134") |
890 |
930 |
891 def __checkNoBlankLineBefore(self, docstringContext, context): |
931 def __checkNoBlankLineBefore(self, docstringContext, context): |
892 """ |
932 """ |
893 Private method to check, that function/method docstrings are not |
933 Private method to check, that function/method docstrings are not |
894 preceded by a blank line. |
934 preceded by a blank line. |
895 |
935 |
896 @param docstringContext docstring context (DocStyleContext) |
936 @param docstringContext docstring context (DocStyleContext) |
897 @param context context of the docstring (DocStyleContext) |
937 @param context context of the docstring (DocStyleContext) |
898 """ |
938 """ |
899 if docstringContext is None: |
939 if docstringContext is None: |
900 return |
940 return |
901 |
941 |
902 contextLines = context.source() |
942 contextLines = context.source() |
903 cti = 0 |
943 cti = 0 |
904 while ( |
944 while cti < len(contextLines) and not contextLines[cti].strip().startswith( |
905 cti < len(contextLines) and |
945 ('"""', 'r"""', 'u"""', "'''", "r'''", "u'''") |
906 not contextLines[cti].strip().startswith( |
|
907 ('"""', 'r"""', 'u"""', "'''", "r'''", "u'''")) |
|
908 ): |
946 ): |
909 cti += 1 |
947 cti += 1 |
910 if cti == len(contextLines): |
948 if cti == len(contextLines): |
911 return |
949 return |
912 |
950 |
913 if not contextLines[cti - 1].strip(): |
951 if not contextLines[cti - 1].strip(): |
914 self.__error(docstringContext.start(), 0, "D141") |
952 self.__error(docstringContext.start(), 0, "D141") |
915 |
953 |
916 def __checkBlankBeforeAndAfterClass(self, docstringContext, context): |
954 def __checkBlankBeforeAndAfterClass(self, docstringContext, context): |
917 """ |
955 """ |
918 Private method to check, that class docstrings have one |
956 Private method to check, that class docstrings have one |
919 blank line around them. |
957 blank line around them. |
920 |
958 |
921 @param docstringContext docstring context (DocStyleContext) |
959 @param docstringContext docstring context (DocStyleContext) |
922 @param context context of the docstring (DocStyleContext) |
960 @param context context of the docstring (DocStyleContext) |
923 """ |
961 """ |
924 if docstringContext is None: |
962 if docstringContext is None: |
925 return |
963 return |
926 |
964 |
927 contextLines = context.source() |
965 contextLines = context.source() |
928 cti = 0 |
966 cti = 0 |
929 while ( |
967 while cti < len(contextLines) and not contextLines[cti].strip().startswith( |
930 cti < len(contextLines) and |
968 ('"""', 'r"""', 'u"""', "'''", "r'''", "u'''") |
931 not contextLines[cti].strip().startswith( |
|
932 ('"""', 'r"""', 'u"""', "'''", "r'''", "u'''")) |
|
933 ): |
969 ): |
934 cti += 1 |
970 cti += 1 |
935 if cti == len(contextLines): |
971 if cti == len(contextLines): |
936 return |
972 return |
937 |
973 |
938 start = cti |
974 start = cti |
939 if contextLines[cti].strip() in ( |
975 if contextLines[cti].strip() in ('"""', 'r"""', 'u"""', "'''", "r'''", "u'''"): |
940 '"""', 'r"""', 'u"""', "'''", "r'''", "u'''"): |
|
941 # it is a multi line docstring |
976 # it is a multi line docstring |
942 cti += 1 |
977 cti += 1 |
943 |
978 |
944 while ( |
979 while cti < len(contextLines) and not contextLines[cti].strip().endswith( |
945 cti < len(contextLines) and |
980 ('"""', "'''") |
946 not contextLines[cti].strip().endswith(('"""', "'''")) |
|
947 ): |
981 ): |
948 cti += 1 |
982 cti += 1 |
949 end = cti |
983 end = cti |
950 if cti >= len(contextLines) - 1: |
984 if cti >= len(contextLines) - 1: |
951 return |
985 return |
952 |
986 |
953 if contextLines[start - 1].strip(): |
987 if contextLines[start - 1].strip(): |
954 self.__error(docstringContext.start(), 0, "D142") |
988 self.__error(docstringContext.start(), 0, "D142") |
955 if contextLines[end + 1].strip(): |
989 if contextLines[end + 1].strip(): |
956 self.__error(docstringContext.end(), 0, "D143") |
990 self.__error(docstringContext.end(), 0, "D143") |
957 |
991 |
958 def __checkBlankAfterSummary(self, docstringContext, context): |
992 def __checkBlankAfterSummary(self, docstringContext, context): |
959 """ |
993 """ |
960 Private method to check, that docstring summaries are followed |
994 Private method to check, that docstring summaries are followed |
961 by a blank line. |
995 by a blank line. |
962 |
996 |
963 @param docstringContext docstring context (DocStyleContext) |
997 @param docstringContext docstring context (DocStyleContext) |
964 @param context context of the docstring (DocStyleContext) |
998 @param context context of the docstring (DocStyleContext) |
965 """ |
999 """ |
966 if docstringContext is None: |
1000 if docstringContext is None: |
967 return |
1001 return |
968 |
1002 |
969 docstrings = docstringContext.source() |
1003 docstrings = docstringContext.source() |
970 if len(docstrings) <= 3: |
1004 if len(docstrings) <= 3: |
971 # correct/invalid one-liner |
1005 # correct/invalid one-liner |
972 return |
1006 return |
973 |
1007 |
974 summary, lineNumber = self.__getSummaryLine(docstringContext) |
1008 summary, lineNumber = self.__getSummaryLine(docstringContext) |
975 if ( |
1009 if len(docstrings) > 2 and docstrings[lineNumber + 1].strip(): |
976 len(docstrings) > 2 and |
|
977 docstrings[lineNumber + 1].strip() |
|
978 ): |
|
979 self.__error(docstringContext.start() + lineNumber, 0, "D144") |
1010 self.__error(docstringContext.start() + lineNumber, 0, "D144") |
980 |
1011 |
981 def __checkBlankAfterLastParagraph(self, docstringContext, context): |
1012 def __checkBlankAfterLastParagraph(self, docstringContext, context): |
982 """ |
1013 """ |
983 Private method to check, that the last paragraph of docstrings is |
1014 Private method to check, that the last paragraph of docstrings is |
984 followed by a blank line. |
1015 followed by a blank line. |
985 |
1016 |
986 @param docstringContext docstring context (DocStyleContext) |
1017 @param docstringContext docstring context (DocStyleContext) |
987 @param context context of the docstring (DocStyleContext) |
1018 @param context context of the docstring (DocStyleContext) |
988 """ |
1019 """ |
989 if docstringContext is None: |
1020 if docstringContext is None: |
990 return |
1021 return |
991 |
1022 |
992 docstrings = docstringContext.source() |
1023 docstrings = docstringContext.source() |
993 if len(docstrings) <= 3: |
1024 if len(docstrings) <= 3: |
994 # correct/invalid one-liner |
1025 # correct/invalid one-liner |
995 return |
1026 return |
996 |
1027 |
997 if docstrings[-2].strip(): |
1028 if docstrings[-2].strip(): |
998 self.__error(docstringContext.end(), 0, "D145") |
1029 self.__error(docstringContext.end(), 0, "D145") |
999 |
1030 |
1000 ################################################################## |
1031 ################################################################## |
1001 ## Checking functionality below (eric specific ones) |
1032 ## Checking functionality below (eric specific ones) |
1002 ################################################################## |
1033 ################################################################## |
1003 |
1034 |
1004 def __checkEricQuotesOnSeparateLines(self, docstringContext, context): |
1035 def __checkEricQuotesOnSeparateLines(self, docstringContext, context): |
1005 """ |
1036 """ |
1006 Private method to check, that leading and trailing quotes are on |
1037 Private method to check, that leading and trailing quotes are on |
1007 a line by themselves. |
1038 a line by themselves. |
1008 |
1039 |
1009 @param docstringContext docstring context (DocStyleContext) |
1040 @param docstringContext docstring context (DocStyleContext) |
1010 @param context context of the docstring (DocStyleContext) |
1041 @param context context of the docstring (DocStyleContext) |
1011 """ |
1042 """ |
1012 if docstringContext is None: |
1043 if docstringContext is None: |
1013 return |
1044 return |
1014 |
1045 |
1015 lines = docstringContext.source() |
1046 lines = docstringContext.source() |
1016 if lines[0].strip().strip('ru"\''): |
1047 if lines[0].strip().strip("ru\"'"): |
1017 self.__error(docstringContext.start(), 0, "D221") |
1048 self.__error(docstringContext.start(), 0, "D221") |
1018 if lines[-1].strip().strip('"\''): |
1049 if lines[-1].strip().strip("\"'"): |
1019 self.__error(docstringContext.end(), 0, "D222") |
1050 self.__error(docstringContext.end(), 0, "D222") |
1020 |
1051 |
1021 def __checkEricEndsWithPeriod(self, docstringContext, context): |
1052 def __checkEricEndsWithPeriod(self, docstringContext, context): |
1022 """ |
1053 """ |
1023 Private method to check, that docstring summaries end with a period. |
1054 Private method to check, that docstring summaries end with a period. |
1024 |
1055 |
1025 @param docstringContext docstring context (DocStyleContext) |
1056 @param docstringContext docstring context (DocStyleContext) |
1026 @param context context of the docstring (DocStyleContext) |
1057 @param context context of the docstring (DocStyleContext) |
1027 """ |
1058 """ |
1028 if docstringContext is None: |
1059 if docstringContext is None: |
1029 return |
1060 return |
1030 |
1061 |
1031 summaryLines, lineNumber = self.__getSummaryLines(docstringContext) |
1062 summaryLines, lineNumber = self.__getSummaryLines(docstringContext) |
1032 if summaryLines: |
1063 if summaryLines: |
1033 if summaryLines[-1].lstrip().startswith("@"): |
1064 if summaryLines[-1].lstrip().startswith("@"): |
1034 summaryLines.pop(-1) |
1065 summaryLines.pop(-1) |
1035 summary = " ".join([s.strip() for s in summaryLines if s]) |
1066 summary = " ".join([s.strip() for s in summaryLines if s]) |
1036 if ( |
1067 if ( |
1037 summary and |
1068 summary |
1038 not summary.endswith(".") and |
1069 and not summary.endswith(".") |
1039 summary.split(None, 1)[0].lower() != "constructor" |
1070 and summary.split(None, 1)[0].lower() != "constructor" |
1040 ): |
1071 ): |
1041 self.__error( |
1072 self.__error( |
1042 docstringContext.start() + lineNumber + |
1073 docstringContext.start() + lineNumber + len(summaryLines) - 1, |
1043 len(summaryLines) - 1, |
1074 0, |
1044 0, "D231") |
1075 "D231", |
1045 |
1076 ) |
|
1077 |
1046 def __checkEricReturn(self, docstringContext, context): |
1078 def __checkEricReturn(self, docstringContext, context): |
1047 """ |
1079 """ |
1048 Private method to check, that docstrings contain an @return line |
1080 Private method to check, that docstrings contain an @return line |
1049 if they return anything and don't otherwise. |
1081 if they return anything and don't otherwise. |
1050 |
1082 |
1051 @param docstringContext docstring context (DocStyleContext) |
1083 @param docstringContext docstring context (DocStyleContext) |
1052 @param context context of the docstring (DocStyleContext) |
1084 @param context context of the docstring (DocStyleContext) |
1053 """ |
1085 """ |
1054 if docstringContext is None: |
1086 if docstringContext is None: |
1055 return |
1087 return |
1056 |
1088 |
1057 tokens = list( |
1089 tokens = list(tokenize.generate_tokens(StringIO(context.ssource()).readline)) |
1058 tokenize.generate_tokens(StringIO(context.ssource()).readline)) |
1090 return_ = [ |
1059 return_ = [tokens[i + 1][0] for i, token in enumerate(tokens) |
1091 tokens[i + 1][0] for i, token in enumerate(tokens) if token[1] == "return" |
1060 if token[1] == "return"] |
1092 ] |
1061 if "@return" not in docstringContext.ssource(): |
1093 if "@return" not in docstringContext.ssource(): |
1062 if (set(return_) - |
1094 if ( |
1063 {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} != |
1095 set(return_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} |
1064 set()): |
1096 != set() |
|
1097 ): |
1065 self.__error(docstringContext.end(), 0, "D234r") |
1098 self.__error(docstringContext.end(), 0, "D234r") |
1066 else: |
1099 else: |
1067 if (set(return_) - |
1100 if ( |
1068 {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} == |
1101 set(return_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} |
1069 set()): |
1102 == set() |
|
1103 ): |
1070 self.__error(docstringContext.end(), 0, "D235r") |
1104 self.__error(docstringContext.end(), 0, "D235r") |
1071 |
1105 |
1072 def __checkEricYield(self, docstringContext, context): |
1106 def __checkEricYield(self, docstringContext, context): |
1073 """ |
1107 """ |
1074 Private method to check, that docstrings contain an @yield line |
1108 Private method to check, that docstrings contain an @yield line |
1075 if they return anything and don't otherwise. |
1109 if they return anything and don't otherwise. |
1076 |
1110 |
1077 @param docstringContext docstring context (DocStyleContext) |
1111 @param docstringContext docstring context (DocStyleContext) |
1078 @param context context of the docstring (DocStyleContext) |
1112 @param context context of the docstring (DocStyleContext) |
1079 """ |
1113 """ |
1080 if docstringContext is None: |
1114 if docstringContext is None: |
1081 return |
1115 return |
1082 |
1116 |
1083 tokens = list( |
1117 tokens = list(tokenize.generate_tokens(StringIO(context.ssource()).readline)) |
1084 tokenize.generate_tokens(StringIO(context.ssource()).readline)) |
1118 yield_ = [ |
1085 yield_ = [tokens[i + 1][0] for i, token in enumerate(tokens) |
1119 tokens[i + 1][0] for i, token in enumerate(tokens) if token[1] == "yield" |
1086 if token[1] == "yield"] |
1120 ] |
1087 if "@yield" not in docstringContext.ssource(): |
1121 if "@yield" not in docstringContext.ssource(): |
1088 if (set(yield_) - |
1122 if set(yield_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} != set(): |
1089 {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} != |
|
1090 set()): |
|
1091 self.__error(docstringContext.end(), 0, "D234y") |
1123 self.__error(docstringContext.end(), 0, "D234y") |
1092 else: |
1124 else: |
1093 if (set(yield_) - |
1125 if set(yield_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} == set(): |
1094 {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} == |
|
1095 set()): |
|
1096 self.__error(docstringContext.end(), 0, "D235y") |
1126 self.__error(docstringContext.end(), 0, "D235y") |
1097 |
1127 |
1098 def __checkEricFunctionArguments(self, docstringContext, context): |
1128 def __checkEricFunctionArguments(self, docstringContext, context): |
1099 """ |
1129 """ |
1100 Private method to check, that docstrings contain an @param and/or |
1130 Private method to check, that docstrings contain an @param and/or |
1101 @keyparam line for each argument. |
1131 @keyparam line for each argument. |
1102 |
1132 |
1103 @param docstringContext docstring context (DocStyleContext) |
1133 @param docstringContext docstring context (DocStyleContext) |
1104 @param context context of the docstring (DocStyleContext) |
1134 @param context context of the docstring (DocStyleContext) |
1105 """ |
1135 """ |
1106 if docstringContext is None: |
1136 if docstringContext is None: |
1107 return |
1137 return |
1108 |
1138 |
1109 try: |
1139 try: |
1110 tree = ast.parse(context.ssource()) |
1140 tree = ast.parse(context.ssource()) |
1111 except (SyntaxError, TypeError): |
1141 except (SyntaxError, TypeError): |
1112 return |
1142 return |
1113 if (isinstance(tree, ast.Module) and len(tree.body) == 1 and |
1143 if ( |
1114 isinstance(tree.body[0], |
1144 isinstance(tree, ast.Module) |
1115 (ast.FunctionDef, ast.AsyncFunctionDef))): |
1145 and len(tree.body) == 1 |
|
1146 and isinstance(tree.body[0], (ast.FunctionDef, ast.AsyncFunctionDef)) |
|
1147 ): |
1116 functionDef = tree.body[0] |
1148 functionDef = tree.body[0] |
1117 argNames, kwNames = self.__getArgNames(functionDef) |
1149 argNames, kwNames = self.__getArgNames(functionDef) |
1118 if "self" in argNames: |
1150 if "self" in argNames: |
1119 argNames.remove("self") |
1151 argNames.remove("self") |
1120 if "cls" in argNames: |
1152 if "cls" in argNames: |
1121 argNames.remove("cls") |
1153 argNames.remove("cls") |
1122 |
1154 |
1123 docstring = docstringContext.ssource() |
1155 docstring = docstringContext.ssource() |
1124 if (docstring.count("@param") + docstring.count("@keyparam") < |
1156 if docstring.count("@param") + docstring.count("@keyparam") < len( |
1125 len(argNames + kwNames)): |
1157 argNames + kwNames |
|
1158 ): |
1126 self.__error(docstringContext.end(), 0, "D236") |
1159 self.__error(docstringContext.end(), 0, "D236") |
1127 elif (docstring.count("@param") + docstring.count("@keyparam") > |
1160 elif docstring.count("@param") + docstring.count("@keyparam") > len( |
1128 len(argNames + kwNames)): |
1161 argNames + kwNames |
|
1162 ): |
1129 self.__error(docstringContext.end(), 0, "D237") |
1163 self.__error(docstringContext.end(), 0, "D237") |
1130 else: |
1164 else: |
1131 # extract @param and @keyparam from docstring |
1165 # extract @param and @keyparam from docstring |
1132 args = [] |
1166 args = [] |
1133 kwargs = [] |
1167 kwargs = [] |
1137 if len(paramParts) >= 2: |
1171 if len(paramParts) >= 2: |
1138 at, name = paramParts[:2] |
1172 at, name = paramParts[:2] |
1139 if at == "@keyparam": |
1173 if at == "@keyparam": |
1140 kwargs.append(name.lstrip("*")) |
1174 kwargs.append(name.lstrip("*")) |
1141 args.append(name.lstrip("*")) |
1175 args.append(name.lstrip("*")) |
1142 |
1176 |
1143 # do the checks |
1177 # do the checks |
1144 for name in kwNames: |
1178 for name in kwNames: |
1145 if name not in kwargs: |
1179 if name not in kwargs: |
1146 self.__error(docstringContext.end(), 0, "D238") |
1180 self.__error(docstringContext.end(), 0, "D238") |
1147 return |
1181 return |
1148 if argNames + kwNames != args: |
1182 if argNames + kwNames != args: |
1149 self.__error(docstringContext.end(), 0, "D239") |
1183 self.__error(docstringContext.end(), 0, "D239") |
1150 |
1184 |
1151 def __checkEricException(self, docstringContext, context): |
1185 def __checkEricException(self, docstringContext, context): |
1152 """ |
1186 """ |
1153 Private method to check, that docstrings contain an @exception line |
1187 Private method to check, that docstrings contain an @exception line |
1154 if they raise an exception and don't otherwise. |
1188 if they raise an exception and don't otherwise. |
1155 |
1189 |
1156 Note: This method also checks the raised and documented exceptions for |
1190 Note: This method also checks the raised and documented exceptions for |
1157 completeness (i.e. raised exceptions that are not documented or |
1191 completeness (i.e. raised exceptions that are not documented or |
1158 documented exceptions that are not raised) |
1192 documented exceptions that are not raised) |
1159 |
1193 |
1160 @param docstringContext docstring context (DocStyleContext) |
1194 @param docstringContext docstring context (DocStyleContext) |
1161 @param context context of the docstring (DocStyleContext) |
1195 @param context context of the docstring (DocStyleContext) |
1162 """ |
1196 """ |
1163 if docstringContext is None: |
1197 if docstringContext is None: |
1164 return |
1198 return |
1165 |
1199 |
1166 tokens = list( |
1200 tokens = list(tokenize.generate_tokens(StringIO(context.ssource()).readline)) |
1167 tokenize.generate_tokens(StringIO(context.ssource()).readline)) |
|
1168 exceptions = set() |
1201 exceptions = set() |
1169 raisedExceptions = set() |
1202 raisedExceptions = set() |
1170 tokensLen = len(tokens) |
1203 tokensLen = len(tokens) |
1171 for i, token in enumerate(tokens): |
1204 for i, token in enumerate(tokens): |
1172 if token[1] == "raise": |
1205 if token[1] == "raise": |
1173 exceptions.add(tokens[i + 1][0]) |
1206 exceptions.add(tokens[i + 1][0]) |
1174 if tokens[i + 1][0] == tokenize.NAME: |
1207 if tokens[i + 1][0] == tokenize.NAME: |
1175 if ( |
1208 if tokensLen > (i + 2) and tokens[i + 2][1] == ".": |
1176 tokensLen > (i + 2) and |
1209 raisedExceptions.add( |
1177 tokens[i + 2][1] == "." |
1210 "{0}.{1}".format(tokens[i + 1][1], tokens[i + 3][1]) |
1178 ): |
1211 ) |
1179 raisedExceptions.add("{0}.{1}".format( |
|
1180 tokens[i + 1][1], tokens[i + 3][1])) |
|
1181 else: |
1212 else: |
1182 raisedExceptions.add(tokens[i + 1][1]) |
1213 raisedExceptions.add(tokens[i + 1][1]) |
1183 |
1214 |
1184 if ( |
1215 if ( |
1185 "@exception" not in docstringContext.ssource() and |
1216 "@exception" not in docstringContext.ssource() |
1186 "@throws" not in docstringContext.ssource() and |
1217 and "@throws" not in docstringContext.ssource() |
1187 "@raise" not in docstringContext.ssource() |
1218 and "@raise" not in docstringContext.ssource() |
1188 ): |
1219 ): |
1189 if (exceptions - |
1220 if exceptions - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} != set(): |
1190 {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} != |
|
1191 set()): |
|
1192 self.__error(docstringContext.end(), 0, "D250") |
1221 self.__error(docstringContext.end(), 0, "D250") |
1193 else: |
1222 else: |
1194 if (exceptions - |
1223 if exceptions - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} == set(): |
1195 {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} == |
|
1196 set()): |
|
1197 self.__error(docstringContext.end(), 0, "D251") |
1224 self.__error(docstringContext.end(), 0, "D251") |
1198 else: |
1225 else: |
1199 # step 1: extract documented exceptions |
1226 # step 1: extract documented exceptions |
1200 documentedExceptions = set() |
1227 documentedExceptions = set() |
1201 for line in docstringContext.source(): |
1228 for line in docstringContext.source(): |
1202 line = line.strip() |
1229 line = line.strip() |
1203 if line.startswith(("@exception", "@throws", "@raise")): |
1230 if line.startswith(("@exception", "@throws", "@raise")): |
1204 exceptionTokens = line.split(None, 2) |
1231 exceptionTokens = line.split(None, 2) |
1205 if len(exceptionTokens) >= 2: |
1232 if len(exceptionTokens) >= 2: |
1206 documentedExceptions.add(exceptionTokens[1]) |
1233 documentedExceptions.add(exceptionTokens[1]) |
1207 |
1234 |
1208 # step 2: report undocumented exceptions |
1235 # step 2: report undocumented exceptions |
1209 for exception in raisedExceptions: |
1236 for exception in raisedExceptions: |
1210 if exception not in documentedExceptions: |
1237 if exception not in documentedExceptions: |
1211 self.__error(docstringContext.end(), 0, "D252", |
1238 self.__error(docstringContext.end(), 0, "D252", exception) |
1212 exception) |
1239 |
1213 |
|
1214 # step 3: report undefined signals |
1240 # step 3: report undefined signals |
1215 for exception in documentedExceptions: |
1241 for exception in documentedExceptions: |
1216 if exception not in raisedExceptions: |
1242 if exception not in raisedExceptions: |
1217 self.__error(docstringContext.end(), 0, "D253", |
1243 self.__error(docstringContext.end(), 0, "D253", exception) |
1218 exception) |
1244 |
1219 |
|
1220 def __checkEricSignal(self, docstringContext, context): |
1245 def __checkEricSignal(self, docstringContext, context): |
1221 """ |
1246 """ |
1222 Private method to check, that docstrings contain an @signal line |
1247 Private method to check, that docstrings contain an @signal line |
1223 if they define signals and don't otherwise. |
1248 if they define signals and don't otherwise. |
1224 |
1249 |
1225 Note: This method also checks the defined and documented signals for |
1250 Note: This method also checks the defined and documented signals for |
1226 completeness (i.e. defined signals that are not documented or |
1251 completeness (i.e. defined signals that are not documented or |
1227 documented signals that are not defined) |
1252 documented signals that are not defined) |
1228 |
1253 |
1229 @param docstringContext docstring context (DocStyleContext) |
1254 @param docstringContext docstring context (DocStyleContext) |
1230 @param context context of the docstring (DocStyleContext) |
1255 @param context context of the docstring (DocStyleContext) |
1231 """ |
1256 """ |
1232 if docstringContext is None: |
1257 if docstringContext is None: |
1233 return |
1258 return |
1234 |
1259 |
1235 tokens = list( |
1260 tokens = list(tokenize.generate_tokens(StringIO(context.ssource()).readline)) |
1236 tokenize.generate_tokens(StringIO(context.ssource()).readline)) |
|
1237 definedSignals = set() |
1261 definedSignals = set() |
1238 for i, token in enumerate(tokens): |
1262 for i, token in enumerate(tokens): |
1239 if token[1] in ("pyqtSignal", "Signal"): |
1263 if token[1] in ("pyqtSignal", "Signal"): |
1240 if tokens[i - 1][1] == "." and tokens[i - 2][1] == "QtCore": |
1264 if tokens[i - 1][1] == "." and tokens[i - 2][1] == "QtCore": |
1241 definedSignals.add(tokens[i - 4][1]) |
1265 definedSignals.add(tokens[i - 4][1]) |
1242 elif tokens[i - 1][1] == "=": |
1266 elif tokens[i - 1][1] == "=": |
1243 definedSignals.add(tokens[i - 2][1]) |
1267 definedSignals.add(tokens[i - 2][1]) |
1244 |
1268 |
1245 if "@signal" not in docstringContext.ssource() and definedSignals: |
1269 if "@signal" not in docstringContext.ssource() and definedSignals: |
1246 self.__error(docstringContext.end(), 0, "D260") |
1270 self.__error(docstringContext.end(), 0, "D260") |
1247 elif "@signal" in docstringContext.ssource(): |
1271 elif "@signal" in docstringContext.ssource(): |
1248 if not definedSignals: |
1272 if not definedSignals: |
1249 self.__error(docstringContext.end(), 0, "D261") |
1273 self.__error(docstringContext.end(), 0, "D261") |
1342 else: |
1363 else: |
1343 if not contextLines[start - 1].strip(): |
1364 if not contextLines[start - 1].strip(): |
1344 self.__error(docstringContext.start(), 0, "D244") |
1365 self.__error(docstringContext.start(), 0, "D244") |
1345 if not contextLines[end + 1].strip(): |
1366 if not contextLines[end + 1].strip(): |
1346 if ( |
1367 if ( |
1347 self.__docType == "eric_black" and |
1368 self.__docType == "eric_black" |
1348 len(contextLines) > end + 2 and |
1369 and len(contextLines) > end + 2 |
1349 contextLines[end + 2].strip().startswith("def ") |
1370 and contextLines[end + 2].strip().startswith("def ") |
1350 ): |
1371 ): |
1351 return |
1372 return |
1352 |
1373 |
1353 self.__error(docstringContext.end(), 0, "D245") |
1374 self.__error(docstringContext.end(), 0, "D245") |
1354 |
1375 |
1355 def __checkEricNBlankAfterLastParagraph(self, docstringContext, context): |
1376 def __checkEricNBlankAfterLastParagraph(self, docstringContext, context): |
1356 """ |
1377 """ |
1357 Private method to check, that the last paragraph of docstrings is |
1378 Private method to check, that the last paragraph of docstrings is |
1358 not followed by a blank line. |
1379 not followed by a blank line. |
1359 |
1380 |
1360 @param docstringContext docstring context (DocStyleContext) |
1381 @param docstringContext docstring context (DocStyleContext) |
1361 @param context context of the docstring (DocStyleContext) |
1382 @param context context of the docstring (DocStyleContext) |
1362 """ |
1383 """ |
1363 if docstringContext is None: |
1384 if docstringContext is None: |
1364 return |
1385 return |
1365 |
1386 |
1366 docstrings = docstringContext.source() |
1387 docstrings = docstringContext.source() |
1367 if len(docstrings) <= 3: |
1388 if len(docstrings) <= 3: |
1368 # correct/invalid one-liner |
1389 # correct/invalid one-liner |
1369 return |
1390 return |
1370 |
1391 |
1371 if not docstrings[-2].strip(): |
1392 if not docstrings[-2].strip(): |
1372 self.__error(docstringContext.end(), 0, "D247") |
1393 self.__error(docstringContext.end(), 0, "D247") |
1373 |
1394 |
1374 def __checkEricSummary(self, docstringContext, context): |
1395 def __checkEricSummary(self, docstringContext, context): |
1375 """ |
1396 """ |
1376 Private method to check, that method docstring summaries start with |
1397 Private method to check, that method docstring summaries start with |
1377 specific words. |
1398 specific words. |
1378 |
1399 |
1379 @param docstringContext docstring context (DocStyleContext) |
1400 @param docstringContext docstring context (DocStyleContext) |
1380 @param context context of the docstring (DocStyleContext) |
1401 @param context context of the docstring (DocStyleContext) |
1381 """ |
1402 """ |
1382 if docstringContext is None: |
1403 if docstringContext is None: |
1383 return |
1404 return |
1384 |
1405 |
1385 summary, lineNumber = self.__getSummaryLine(docstringContext) |
1406 summary, lineNumber = self.__getSummaryLine(docstringContext) |
1386 if summary: |
1407 if summary: |
1387 # check, if the first word is 'Constructor', 'Public', |
1408 # check, if the first word is 'Constructor', 'Public', |
1388 # 'Protected' or 'Private' |
1409 # 'Protected' or 'Private' |
1389 functionName, arguments = ( |
1410 functionName, arguments = ( |
1390 context.source()[0].lstrip().split()[1].split("(", 1) |
1411 context.source()[0].lstrip().split()[1].split("(", 1) |
1391 ) |
1412 ) |
1392 firstWord = summary.strip().split(None, 1)[0].lower() |
1413 firstWord = summary.strip().split(None, 1)[0].lower() |
1393 if functionName == '__init__': |
1414 if functionName == "__init__": |
1394 if firstWord != 'constructor': |
1415 if firstWord != "constructor": |
1395 self.__error(docstringContext.start() + lineNumber, 0, |
1416 self.__error( |
1396 "D232", 'constructor') |
1417 docstringContext.start() + lineNumber, 0, "D232", "constructor" |
1397 elif ( |
1418 ) |
1398 functionName.startswith('__') and |
1419 elif functionName.startswith("__") and functionName.endswith("__"): |
1399 functionName.endswith('__') |
1420 if firstWord != "special": |
1400 ): |
1421 self.__error( |
1401 if firstWord != 'special': |
1422 docstringContext.start() + lineNumber, 0, "D232", "special" |
1402 self.__error(docstringContext.start() + lineNumber, 0, |
1423 ) |
1403 "D232", 'special') |
|
1404 elif context.special() == "staticmethod": |
1424 elif context.special() == "staticmethod": |
1405 secondWord = summary.strip().split(None, 2)[1].lower() |
1425 secondWord = summary.strip().split(None, 2)[1].lower() |
1406 if firstWord != 'static' and secondWord != 'static': |
1426 if firstWord != "static" and secondWord != "static": |
1407 self.__error(docstringContext.start() + lineNumber, 0, |
1427 self.__error( |
1408 "D232", 'static') |
1428 docstringContext.start() + lineNumber, 0, "D232", "static" |
1409 elif secondWord == 'static': |
1429 ) |
1410 if functionName.startswith(('__', 'on_')): |
1430 elif secondWord == "static": |
1411 if firstWord != 'private': |
1431 if functionName.startswith(("__", "on_")): |
1412 self.__error(docstringContext.start() + lineNumber, |
1432 if firstWord != "private": |
1413 0, "D232", 'private static') |
1433 self.__error( |
1414 elif ( |
1434 docstringContext.start() + lineNumber, |
1415 functionName.startswith('_') or |
1435 0, |
1416 functionName.endswith('Event') |
1436 "D232", |
1417 ): |
1437 "private static", |
1418 if firstWord != 'protected': |
1438 ) |
1419 self.__error(docstringContext.start() + lineNumber, |
1439 elif functionName.startswith("_") or functionName.endswith("Event"): |
1420 0, "D232", 'protected static') |
1440 if firstWord != "protected": |
|
1441 self.__error( |
|
1442 docstringContext.start() + lineNumber, |
|
1443 0, |
|
1444 "D232", |
|
1445 "protected static", |
|
1446 ) |
1421 else: |
1447 else: |
1422 if firstWord != 'public': |
1448 if firstWord != "public": |
1423 self.__error(docstringContext.start() + lineNumber, |
1449 self.__error( |
1424 0, "D232", 'public static') |
1450 docstringContext.start() + lineNumber, |
|
1451 0, |
|
1452 "D232", |
|
1453 "public static", |
|
1454 ) |
1425 elif ( |
1455 elif ( |
1426 arguments.startswith(('cls,', 'cls)')) or |
1456 arguments.startswith(("cls,", "cls)")) |
1427 context.special() == "classmethod" |
1457 or context.special() == "classmethod" |
1428 ): |
1458 ): |
1429 secondWord = summary.strip().split(None, 2)[1].lower() |
1459 secondWord = summary.strip().split(None, 2)[1].lower() |
1430 if firstWord != 'class' and secondWord != 'class': |
1460 if firstWord != "class" and secondWord != "class": |
1431 self.__error(docstringContext.start() + lineNumber, 0, |
1461 self.__error( |
1432 "D232", 'class') |
1462 docstringContext.start() + lineNumber, 0, "D232", "class" |
1433 elif secondWord == 'class': |
1463 ) |
1434 if functionName.startswith(('__', 'on_')): |
1464 elif secondWord == "class": |
1435 if firstWord != 'private': |
1465 if functionName.startswith(("__", "on_")): |
1436 self.__error(docstringContext.start() + lineNumber, |
1466 if firstWord != "private": |
1437 0, "D232", 'private class') |
1467 self.__error( |
1438 elif ( |
1468 docstringContext.start() + lineNumber, |
1439 functionName.startswith('_') or |
1469 0, |
1440 functionName.endswith('Event') |
1470 "D232", |
1441 ): |
1471 "private class", |
1442 if firstWord != 'protected': |
1472 ) |
1443 self.__error(docstringContext.start() + lineNumber, |
1473 elif functionName.startswith("_") or functionName.endswith("Event"): |
1444 0, "D232", 'protected class') |
1474 if firstWord != "protected": |
|
1475 self.__error( |
|
1476 docstringContext.start() + lineNumber, |
|
1477 0, |
|
1478 "D232", |
|
1479 "protected class", |
|
1480 ) |
1445 else: |
1481 else: |
1446 if firstWord != 'public': |
1482 if firstWord != "public": |
1447 self.__error(docstringContext.start() + lineNumber, |
1483 self.__error( |
1448 0, "D232", 'public class') |
1484 docstringContext.start() + lineNumber, |
1449 elif functionName.startswith(('__', 'on_')): |
1485 0, |
1450 if firstWord != 'private': |
1486 "D232", |
1451 self.__error(docstringContext.start() + lineNumber, 0, |
1487 "public class", |
1452 "D232", 'private') |
1488 ) |
1453 elif ( |
1489 elif functionName.startswith(("__", "on_")): |
1454 functionName.startswith('_') or |
1490 if firstWord != "private": |
1455 functionName.endswith('Event') |
1491 self.__error( |
1456 ): |
1492 docstringContext.start() + lineNumber, 0, "D232", "private" |
1457 if firstWord != 'protected': |
1493 ) |
1458 self.__error(docstringContext.start() + lineNumber, 0, |
1494 elif functionName.startswith("_") or functionName.endswith("Event"): |
1459 "D232", 'protected') |
1495 if firstWord != "protected": |
|
1496 self.__error( |
|
1497 docstringContext.start() + lineNumber, 0, "D232", "protected" |
|
1498 ) |
1460 else: |
1499 else: |
1461 if firstWord != 'public': |
1500 if firstWord != "public": |
1462 self.__error(docstringContext.start() + lineNumber, 0, |
1501 self.__error( |
1463 "D232", 'public') |
1502 docstringContext.start() + lineNumber, 0, "D232", "public" |
|
1503 ) |