11 # The routines of the checker class are modeled after the ones found in |
11 # The routines of the checker class are modeled after the ones found in |
12 # pep257.py (version 0.2.4). |
12 # pep257.py (version 0.2.4). |
13 # |
13 # |
14 |
14 |
15 import ast |
15 import ast |
|
16 import collections |
16 import contextlib |
17 import contextlib |
17 import tokenize |
18 import tokenize |
18 |
19 |
19 from io import StringIO |
20 from io import StringIO |
20 |
21 |
21 try: |
22 try: |
22 ast.AsyncFunctionDef # __IGNORE_EXCEPTION__ |
23 ast.AsyncFunctionDef # __IGNORE_EXCEPTION__ |
23 except AttributeError: |
24 except AttributeError: |
24 ast.AsyncFunctionDef = ast.FunctionDef |
25 ast.AsyncFunctionDef = ast.FunctionDef |
|
26 |
|
27 from CodeStyleTopicChecker import CodeStyleTopicChecker |
25 |
28 |
26 |
29 |
27 class DocStyleContext: |
30 class DocStyleContext: |
28 """ |
31 """ |
29 Class implementing the source context. |
32 Class implementing the source context. |
219 @param maxLineLength allowed line length |
223 @param maxLineLength allowed line length |
220 @type int |
224 @type int |
221 @param docType type of the documentation strings (one of 'eric' or 'pep257') |
225 @param docType type of the documentation strings (one of 'eric' or 'pep257') |
222 @type str |
226 @type str |
223 """ |
227 """ |
224 self.__select = tuple(select) |
228 super().__init__( |
225 self.__ignore = tuple(ignore) |
229 DocStyleChecker.Category, |
226 self.__expected = expected[:] |
230 source, |
227 self.__repeat = repeat |
231 filename, |
|
232 None, |
|
233 select, |
|
234 ignore, |
|
235 expected, |
|
236 repeat, |
|
237 [], |
|
238 ) |
|
239 |
228 self.__maxLineLength = maxLineLength |
240 self.__maxLineLength = maxLineLength |
229 self.__docType = docType |
241 self.__docType = docType |
230 self.__filename = filename |
|
231 self.__source = source[:] |
|
232 |
|
233 # statistics counters |
|
234 self.counters = {} |
|
235 |
|
236 # collection of detected errors |
|
237 self.errors = [] |
|
238 |
|
239 self.__lineNumber = 0 |
242 self.__lineNumber = 0 |
240 |
243 |
241 # caches |
244 # caches |
242 self.__functionsCache = None |
245 self.__functionsCache = None |
243 self.__classesCache = None |
246 self.__classesCache = None |
329 (self.__checkEricNBlankAfterLastParagraph, ("D-247",)), |
332 (self.__checkEricNBlankAfterLastParagraph, ("D-247",)), |
330 (self.__checkEricQuotesOnSeparateLines, ("D-222", "D-223")), |
333 (self.__checkEricQuotesOnSeparateLines, ("D-222", "D-223")), |
331 ], |
334 ], |
332 } |
335 } |
333 |
336 |
334 self.__checkers = {} |
337 self.__checkers = collections.defaultdict(list) |
335 for key, checkers in checkersWithCodes.items(): |
338 for key, checkers in checkersWithCodes.items(): |
336 for checker, codes in checkers: |
339 for checker, codes in checkers: |
337 if any(not (code and self.__ignoreCode(code)) for code in codes): |
340 if any( |
338 if key not in self.__checkers: |
341 not (msgCode and self._ignoreCode(msgCode)) for msgCode in codes |
339 self.__checkers[key] = [] |
342 ): |
340 self.__checkers[key].append(checker) |
343 self.__checkers[key].append(checker) |
341 |
344 |
342 def __ignoreCode(self, code): |
345 def addError(self, lineNumber, offset, msgCode, *args): |
343 """ |
346 """ |
344 Private method to check if the error code should be ignored. |
347 Public method to record an issue. |
345 |
348 |
346 @param code message code to check for |
349 @param lineNumber line number of the issue (zero based) |
347 @type str |
|
348 @return flag indicating to ignore the given code |
|
349 @rtype bool |
|
350 """ |
|
351 return code in self.__ignore or ( |
|
352 code.startswith(self.__ignore) and not code.startswith(self.__select) |
|
353 ) |
|
354 |
|
355 def __error(self, lineNumber, offset, code, *args): |
|
356 """ |
|
357 Private method to record an issue. |
|
358 |
|
359 @param lineNumber line number of the issue |
|
360 @type int |
350 @type int |
361 @param offset position within line of the issue |
351 @param offset position within line of the issue |
362 @type int |
352 @type int |
363 @param code message code |
353 @param msgCode message code |
364 @type str |
354 @type str |
365 @param args arguments for the message |
355 @param args arguments for the message |
366 @type list |
356 @type list |
367 """ |
357 """ |
368 if self.__ignoreCode(code): |
358 # call super class method with one based line number |
369 return |
359 super().addError(lineNumber + 1, offset, msgCode, *args) |
370 |
|
371 if code in self.counters: |
|
372 self.counters[code] += 1 |
|
373 else: |
|
374 self.counters[code] = 1 |
|
375 |
|
376 # Don't care about expected codes |
|
377 if code in self.__expected: |
|
378 return |
|
379 |
|
380 if code and (self.counters[code] == 1 or self.__repeat): |
|
381 # record the issue with one based line number |
|
382 self.errors.append( |
|
383 { |
|
384 "file": self.__filename, |
|
385 "line": lineNumber + 1, |
|
386 "offset": offset, |
|
387 "code": code, |
|
388 "args": args, |
|
389 } |
|
390 ) |
|
391 |
360 |
392 def __resetReadline(self): |
361 def __resetReadline(self): |
393 """ |
362 """ |
394 Private method to reset the internal readline function. |
363 Private method to reset the internal readline function. |
395 """ |
364 """ |
401 |
370 |
402 @return next line of source |
371 @return next line of source |
403 @rtype str |
372 @rtype str |
404 """ |
373 """ |
405 self.__lineNumber += 1 |
374 self.__lineNumber += 1 |
406 if self.__lineNumber > len(self.__source): |
375 if self.__lineNumber > len(self.source): |
407 return "" |
376 return "" |
408 return self.__source[self.__lineNumber - 1] |
377 return self.source[self.__lineNumber - 1] |
409 |
378 |
410 def run(self): |
379 def run(self): |
411 """ |
380 """ |
412 Public method to check the given source for violations of doc string |
381 Public method to check the given source for violations of doc string |
413 conventions. |
382 conventions. |
414 """ |
383 """ |
415 if not self.__filename: |
384 if not self.filename: |
416 # don't do anything, if essential data is missing |
385 # don't do anything, if essential data is missing |
417 return |
386 return |
418 |
387 |
419 if not self.__checkers: |
388 if not self.__checkers: |
420 # don't do anything, if no codes were selected |
389 # don't do anything, if no codes were selected |
421 return |
390 return |
422 |
391 |
423 for keyword in self.__keywords: |
392 for key in self.__keywords: |
424 if keyword in self.__checkers: |
393 if key in self.__checkers: |
425 for check in self.__checkers[keyword]: |
394 for check in self.__checkers[key]: |
426 for context in self.__parseContexts(keyword): |
395 for context in self.__parseContexts(key): |
427 docstring = self.__parseDocstring(context, keyword) |
396 docstring = self.__parseDocstring(context, key) |
428 check(docstring, context) |
397 check(docstring, context) |
429 |
398 |
430 def __getSummaryLine(self, docstringContext): |
399 def __getSummaryLine(self, docstringContext): |
431 """ |
400 """ |
432 Private method to extract the summary line. |
401 Private method to extract the summary line. |
597 start = line - 1, char |
566 start = line - 1, char |
598 while not (kind == tokenize.DEDENT and value == "" and char == 0): |
567 while not (kind == tokenize.DEDENT and value == "" and char == 0): |
599 kind, value, (line, char), _, _ = next(tokenGenerator) |
568 kind, value, (line, char), _, _ = next(tokenGenerator) |
600 end = line - 1, char |
569 end = line - 1, char |
601 contexts.append( |
570 contexts.append( |
602 DocStyleContext(self.__source[start[0] : end[0]], start[0], keyword) |
571 DocStyleContext(self.source[start[0] : end[0]], start[0], keyword) |
603 ) |
572 ) |
604 except StopIteration: |
573 except StopIteration: |
605 return contexts |
574 return contexts |
606 |
575 |
607 def __parseFunctions(self): |
576 def __parseFunctions(self): |
674 ) |
643 ) |
675 end = line - 1, char |
644 end = line - 1, char |
676 startLine = classContext.start() + start[0] |
645 startLine = classContext.start() + start[0] |
677 endLine = classContext.start() + end[0] |
646 endLine = classContext.start() + end[0] |
678 context = DocStyleContext( |
647 context = DocStyleContext( |
679 self.__source[startLine:endLine], startLine, "def" |
648 self.source[startLine:endLine], startLine, "def" |
680 ) |
649 ) |
681 if startLine > 0: |
650 if startLine > 0: |
682 if self.__source[startLine - 1].strip() == "@staticmethod": |
651 if self.source[startLine - 1].strip() == "@staticmethod": |
683 context.setSpecial("staticmethod") |
652 context.setSpecial("staticmethod") |
684 elif self.__source[startLine - 1].strip() == "@classmethod": |
653 elif self.source[startLine - 1].strip() == "@classmethod": |
685 context.setSpecial("classmethod") |
654 context.setSpecial("classmethod") |
686 contexts.append(context) |
655 contexts.append(context) |
687 self.__methodsCache = contexts |
656 self.__methodsCache = contexts |
688 |
657 |
689 return self.__methodsCache |
658 return self.__methodsCache |
696 @type str |
665 @type str |
697 @return requested contexts |
666 @return requested contexts |
698 @rtype list of DocStyleContext |
667 @rtype list of DocStyleContext |
699 """ |
668 """ |
700 if kind == "moduleDocstring": |
669 if kind == "moduleDocstring": |
701 return [DocStyleContext(self.__source, 0, "module")] |
670 return [DocStyleContext(self.source, 0, "module")] |
702 if kind == "functionDocstring": |
671 if kind == "functionDocstring": |
703 return self.__parseFunctions() |
672 return self.__parseFunctions() |
704 if kind == "classDocstring": |
673 if kind == "classDocstring": |
705 return self.__parseClasses() |
674 return self.__parseClasses() |
706 if kind == "methodDocstring": |
675 if kind == "methodDocstring": |
707 return self.__parseMethods() |
676 return self.__parseMethods() |
708 if kind == "defDocstring": |
677 if kind == "defDocstring": |
709 return self.__parseFunctions() + self.__parseMethods() |
678 return self.__parseFunctions() + self.__parseMethods() |
710 if kind == "docstring": |
679 if kind == "docstring": |
711 return ( |
680 return ( |
712 [DocStyleContext(self.__source, 0, "module")] |
681 [DocStyleContext(self.source, 0, "module")] |
713 + self.__parseFunctions() |
682 + self.__parseFunctions() |
714 + self.__parseClasses() |
683 + self.__parseClasses() |
715 + self.__parseMethods() |
684 + self.__parseMethods() |
716 ) |
685 ) |
717 return [] # fall back |
686 return [] # fall back |
728 @type DocStyleContext |
697 @type DocStyleContext |
729 @param context context of the docstring |
698 @param context context of the docstring |
730 @type DocStyleContext |
699 @type DocStyleContext |
731 """ |
700 """ |
732 if docstringContext is None: |
701 if docstringContext is None: |
733 self.__error(context.start(), 0, "D-101") |
702 self.addError(context.start(), 0, "D-101") |
734 return |
703 return |
735 |
704 |
736 docstring = docstringContext.ssource() |
705 docstring = docstringContext.ssource() |
737 if not docstring or not docstring.strip() or not docstring.strip("'\""): |
706 if not docstring or not docstring.strip() or not docstring.strip("'\""): |
738 self.__error(context.start(), 0, "D-101") |
707 self.addError(context.start(), 0, "D-101") |
739 |
708 |
740 if ( |
709 if ( |
741 self.__docType == "eric" |
710 self.__docType == "eric" |
742 and docstring.strip("'\"").strip() == "Module documentation goes here." |
711 and docstring.strip("'\"").strip() == "Module documentation goes here." |
743 ): |
712 ): |
744 self.__error(docstringContext.end(), 0, "D-201") |
713 self.addError(docstringContext.end(), 0, "D-201") |
745 return |
714 return |
746 |
715 |
747 def __checkFunctionDocstring(self, docstringContext, context): |
716 def __checkFunctionDocstring(self, docstringContext, context): |
748 """ |
717 """ |
749 Private method to check, that all public functions and methods |
718 Private method to check, that all public functions and methods |
762 code = "D-103" |
731 code = "D-103" |
763 else: |
732 else: |
764 code = "D-102" |
733 code = "D-102" |
765 |
734 |
766 if docstringContext is None: |
735 if docstringContext is None: |
767 self.__error(context.start(), 0, code) |
736 self.addError(context.start(), 0, code) |
768 return |
737 return |
769 |
738 |
770 docstring = docstringContext.ssource() |
739 docstring = docstringContext.ssource() |
771 if not docstring or not docstring.strip() or not docstring.strip("'\""): |
740 if not docstring or not docstring.strip() or not docstring.strip("'\""): |
772 self.__error(context.start(), 0, code) |
741 self.addError(context.start(), 0, code) |
773 |
742 |
774 if self.__docType == "eric": |
743 if self.__docType == "eric": |
775 if docstring.strip("'\"").strip() == "Function documentation goes here.": |
744 if docstring.strip("'\"").strip() == "Function documentation goes here.": |
776 self.__error(docstringContext.end(), 0, "D-202.1") |
745 self.addError(docstringContext.end(), 0, "D-202.1") |
777 return |
746 return |
778 |
747 |
779 if "DESCRIPTION" in docstring or "TYPE" in docstring: |
748 if "DESCRIPTION" in docstring or "TYPE" in docstring: |
780 self.__error(docstringContext.end(), 0, "D-202.2") |
749 self.addError(docstringContext.end(), 0, "D-202.2") |
781 return |
750 return |
782 |
751 |
783 def __checkClassDocstring(self, docstringContext, context): |
752 def __checkClassDocstring(self, docstringContext, context): |
784 """ |
753 """ |
785 Private method to check, that all public functions and methods |
754 Private method to check, that all public functions and methods |
798 code = "D-105" |
767 code = "D-105" |
799 else: |
768 else: |
800 code = "D-104" |
769 code = "D-104" |
801 |
770 |
802 if docstringContext is None: |
771 if docstringContext is None: |
803 self.__error(context.start(), 0, code) |
772 self.addError(context.start(), 0, code) |
804 return |
773 return |
805 |
774 |
806 docstring = docstringContext.ssource() |
775 docstring = docstringContext.ssource() |
807 if not docstring or not docstring.strip() or not docstring.strip("'\""): |
776 if not docstring or not docstring.strip() or not docstring.strip("'\""): |
808 self.__error(context.start(), 0, code) |
777 self.addError(context.start(), 0, code) |
809 return |
778 return |
810 |
779 |
811 if ( |
780 if ( |
812 self.__docType == "eric" |
781 self.__docType == "eric" |
813 and docstring.strip("'\"").strip() == "Class documentation goes here." |
782 and docstring.strip("'\"").strip() == "Class documentation goes here." |
814 ): |
783 ): |
815 self.__error(docstringContext.end(), 0, "D-206") |
784 self.addError(docstringContext.end(), 0, "D-206") |
816 return |
785 return |
817 |
786 |
818 def __checkTripleDoubleQuotes(self, docstringContext, _context): |
787 def __checkTripleDoubleQuotes(self, docstringContext, _context): |
819 """ |
788 """ |
820 Private method to check, that all docstrings are surrounded |
789 Private method to check, that all docstrings are surrounded |
828 if docstringContext is None: |
797 if docstringContext is None: |
829 return |
798 return |
830 |
799 |
831 docstring = docstringContext.ssource().strip() |
800 docstring = docstringContext.ssource().strip() |
832 if not docstring.startswith(('"""', 'r"""', 'u"""')): |
801 if not docstring.startswith(('"""', 'r"""', 'u"""')): |
833 self.__error(docstringContext.start(), 0, "D-111") |
802 self.addError(docstringContext.start(), 0, "D-111") |
834 |
803 |
835 def __checkBackslashes(self, docstringContext, _context): |
804 def __checkBackslashes(self, docstringContext, _context): |
836 """ |
805 """ |
837 Private method to check, that all docstrings containing |
806 Private method to check, that all docstrings containing |
838 backslashes are surrounded by raw triple double quotes. |
807 backslashes are surrounded by raw triple double quotes. |
845 if docstringContext is None: |
814 if docstringContext is None: |
846 return |
815 return |
847 |
816 |
848 docstring = docstringContext.ssource().strip() |
817 docstring = docstringContext.ssource().strip() |
849 if "\\" in docstring and not docstring.startswith('r"""'): |
818 if "\\" in docstring and not docstring.startswith('r"""'): |
850 self.__error(docstringContext.start(), 0, "D-112") |
819 self.addError(docstringContext.start(), 0, "D-112") |
851 |
820 |
852 def __checkOneLiner(self, docstringContext, context): |
821 def __checkOneLiner(self, docstringContext, context): |
853 """ |
822 """ |
854 Private method to check, that one-liner docstrings fit on |
823 Private method to check, that one-liner docstrings fit on |
855 one line with quotes. |
824 one line with quotes. |
873 modLen += 4 |
842 modLen += 4 |
874 if not nonEmptyLines[0].strip().endswith("."): |
843 if not nonEmptyLines[0].strip().endswith("."): |
875 # account for a trailing dot |
844 # account for a trailing dot |
876 modLen += 1 |
845 modLen += 1 |
877 if modLen <= self.__maxLineLength: |
846 if modLen <= self.__maxLineLength: |
878 self.__error(docstringContext.start(), 0, "D-121") |
847 self.addError(docstringContext.start(), 0, "D-121") |
879 |
848 |
880 def __checkIndent(self, docstringContext, context): |
849 def __checkIndent(self, docstringContext, context): |
881 """ |
850 """ |
882 Private method to check, that docstrings are properly indented. |
851 Private method to check, that docstrings are properly indented. |
883 |
852 |
900 indent = min(len(line) - len(line.strip()) for line in nonEmptyLines) |
869 indent = min(len(line) - len(line.strip()) for line in nonEmptyLines) |
901 expectedIndent = ( |
870 expectedIndent = ( |
902 0 if context.contextType() == "module" else len(context.indent()) + 4 |
871 0 if context.contextType() == "module" else len(context.indent()) + 4 |
903 ) |
872 ) |
904 if indent != expectedIndent: |
873 if indent != expectedIndent: |
905 self.__error(docstringContext.start(), 0, "D-122") |
874 self.addError(docstringContext.start(), 0, "D-122") |
906 |
875 |
907 def __checkSummary(self, docstringContext, _context): |
876 def __checkSummary(self, docstringContext, _context): |
908 """ |
877 """ |
909 Private method to check, that docstring summaries contain some text. |
878 Private method to check, that docstring summaries contain some text. |
910 |
879 |
916 if docstringContext is None: |
885 if docstringContext is None: |
917 return |
886 return |
918 |
887 |
919 summary, lineNumber = self.__getSummaryLine(docstringContext) |
888 summary, lineNumber = self.__getSummaryLine(docstringContext) |
920 if summary == "": |
889 if summary == "": |
921 self.__error(docstringContext.start() + lineNumber, 0, "D-130") |
890 self.addError(docstringContext.start() + lineNumber, 0, "D-130") |
922 |
891 |
923 def __checkEndsWithPeriod(self, docstringContext, _context): |
892 def __checkEndsWithPeriod(self, docstringContext, _context): |
924 """ |
893 """ |
925 Private method to check, that docstring summaries end with a period. |
894 Private method to check, that docstring summaries end with a period. |
926 |
895 |
932 if docstringContext is None: |
901 if docstringContext is None: |
933 return |
902 return |
934 |
903 |
935 summary, lineNumber = self.__getSummaryLine(docstringContext) |
904 summary, lineNumber = self.__getSummaryLine(docstringContext) |
936 if not summary.endswith("."): |
905 if not summary.endswith("."): |
937 self.__error(docstringContext.start() + lineNumber, 0, "D-131") |
906 self.addError(docstringContext.start() + lineNumber, 0, "D-131") |
938 |
907 |
939 def __checkImperativeMood(self, docstringContext, _context): |
908 def __checkImperativeMood(self, docstringContext, _context): |
940 """ |
909 """ |
941 Private method to check, that docstring summaries are in |
910 Private method to check, that docstring summaries are in |
942 imperative mood. |
911 imperative mood. |
951 |
920 |
952 summary, lineNumber = self.__getSummaryLine(docstringContext) |
921 summary, lineNumber = self.__getSummaryLine(docstringContext) |
953 if summary: |
922 if summary: |
954 firstWord = summary.strip().split()[0] |
923 firstWord = summary.strip().split()[0] |
955 if firstWord.endswith("s") and not firstWord.endswith("ss"): |
924 if firstWord.endswith("s") and not firstWord.endswith("ss"): |
956 self.__error(docstringContext.start() + lineNumber, 0, "D-132") |
925 self.addError(docstringContext.start() + lineNumber, 0, "D-132") |
957 |
926 |
958 def __checkNoSignature(self, docstringContext, context): |
927 def __checkNoSignature(self, docstringContext, context): |
959 """ |
928 """ |
960 Private method to check, that docstring summaries don't repeat |
929 Private method to check, that docstring summaries don't repeat |
961 the function's signature. |
930 the function's signature. |
972 summary, lineNumber = self.__getSummaryLine(docstringContext) |
941 summary, lineNumber = self.__getSummaryLine(docstringContext) |
973 if functionName + "(" in summary.replace( |
942 if functionName + "(" in summary.replace( |
974 " ", "" |
943 " ", "" |
975 ) and functionName + "()" not in summary.replace(" ", ""): |
944 ) and functionName + "()" not in summary.replace(" ", ""): |
976 # report only, if it is not an abbreviated form (i.e. function() ) |
945 # report only, if it is not an abbreviated form (i.e. function() ) |
977 self.__error(docstringContext.start() + lineNumber, 0, "D-133") |
946 self.addError(docstringContext.start() + lineNumber, 0, "D-133") |
978 |
947 |
979 def __checkReturnType(self, docstringContext, context): |
948 def __checkReturnType(self, docstringContext, context): |
980 """ |
949 """ |
981 Private method to check, that docstrings mention the return value type. |
950 Private method to check, that docstrings mention the return value type. |
982 |
951 |
999 ] |
968 ] |
1000 if ( |
969 if ( |
1001 set(return_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} |
970 set(return_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} |
1002 != set() |
971 != set() |
1003 ): |
972 ): |
1004 self.__error(docstringContext.end(), 0, "D-134") |
973 self.addError(docstringContext.end(), 0, "D-134") |
1005 |
974 |
1006 def __checkNoBlankLineBefore(self, docstringContext, context): |
975 def __checkNoBlankLineBefore(self, docstringContext, context): |
1007 """ |
976 """ |
1008 Private method to check, that function/method docstrings are not |
977 Private method to check, that function/method docstrings are not |
1009 preceded by a blank line. |
978 preceded by a blank line. |
1024 cti += 1 |
993 cti += 1 |
1025 if cti == len(contextLines): |
994 if cti == len(contextLines): |
1026 return |
995 return |
1027 |
996 |
1028 if not contextLines[cti - 1].strip(): |
997 if not contextLines[cti - 1].strip(): |
1029 self.__error(docstringContext.start(), 0, "D-141") |
998 self.addError(docstringContext.start(), 0, "D-141") |
1030 |
999 |
1031 def __checkBlankBeforeAndAfterClass(self, docstringContext, context): |
1000 def __checkBlankBeforeAndAfterClass(self, docstringContext, context): |
1032 """ |
1001 """ |
1033 Private method to check, that class docstrings have one |
1002 Private method to check, that class docstrings have one |
1034 blank line around them. |
1003 blank line around them. |
1062 end = cti |
1031 end = cti |
1063 if cti >= len(contextLines) - 1: |
1032 if cti >= len(contextLines) - 1: |
1064 return |
1033 return |
1065 |
1034 |
1066 if contextLines[start - 1].strip(): |
1035 if contextLines[start - 1].strip(): |
1067 self.__error(docstringContext.start(), 0, "D-142") |
1036 self.addError(docstringContext.start(), 0, "D-142") |
1068 if contextLines[end + 1].strip(): |
1037 if contextLines[end + 1].strip(): |
1069 self.__error(docstringContext.end(), 0, "D-143") |
1038 self.addError(docstringContext.end(), 0, "D-143") |
1070 |
1039 |
1071 def __checkBlankAfterSummary(self, docstringContext, _context): |
1040 def __checkBlankAfterSummary(self, docstringContext, _context): |
1072 """ |
1041 """ |
1073 Private method to check, that docstring summaries are followed |
1042 Private method to check, that docstring summaries are followed |
1074 by a blank line. |
1043 by a blank line. |
1086 # correct/invalid one-liner |
1055 # correct/invalid one-liner |
1087 return |
1056 return |
1088 |
1057 |
1089 summary, lineNumber = self.__getSummaryLine(docstringContext) |
1058 summary, lineNumber = self.__getSummaryLine(docstringContext) |
1090 if len(docstrings) > 2 and docstrings[lineNumber + 1].strip(): |
1059 if len(docstrings) > 2 and docstrings[lineNumber + 1].strip(): |
1091 self.__error(docstringContext.start() + lineNumber, 0, "D-144") |
1060 self.addError(docstringContext.start() + lineNumber, 0, "D-144") |
1092 |
1061 |
1093 def __checkBlankAfterLastParagraph(self, docstringContext, _context): |
1062 def __checkBlankAfterLastParagraph(self, docstringContext, _context): |
1094 """ |
1063 """ |
1095 Private method to check, that the last paragraph of docstrings is |
1064 Private method to check, that the last paragraph of docstrings is |
1096 followed by a blank line. |
1065 followed by a blank line. |
1107 if len(docstrings) <= 3: |
1076 if len(docstrings) <= 3: |
1108 # correct/invalid one-liner |
1077 # correct/invalid one-liner |
1109 return |
1078 return |
1110 |
1079 |
1111 if docstrings[-2].strip(): |
1080 if docstrings[-2].strip(): |
1112 self.__error(docstringContext.end(), 0, "D-145") |
1081 self.addError(docstringContext.end(), 0, "D-145") |
1113 |
1082 |
1114 ################################################################## |
1083 ################################################################## |
1115 ## Checking functionality below (eric specific ones) |
1084 ## Checking functionality below (eric specific ones) |
1116 ################################################################## |
1085 ################################################################## |
1117 |
1086 |
1128 if docstringContext is None: |
1097 if docstringContext is None: |
1129 return |
1098 return |
1130 |
1099 |
1131 lines = docstringContext.source() |
1100 lines = docstringContext.source() |
1132 if lines[0].strip().strip("ru\"'"): |
1101 if lines[0].strip().strip("ru\"'"): |
1133 self.__error(docstringContext.start(), 0, "D-221") |
1102 self.addError(docstringContext.start(), 0, "D-221") |
1134 if lines[-1].strip().strip("\"'"): |
1103 if lines[-1].strip().strip("\"'"): |
1135 self.__error(docstringContext.end(), 0, "D-222") |
1104 self.addError(docstringContext.end(), 0, "D-222") |
1136 |
1105 |
1137 def __checkEricEndsWithPeriod(self, docstringContext, _context): |
1106 def __checkEricEndsWithPeriod(self, docstringContext, _context): |
1138 """ |
1107 """ |
1139 Private method to check, that docstring summaries end with a period. |
1108 Private method to check, that docstring summaries end with a period. |
1140 |
1109 |
1182 if "@return" not in docstringContext.ssource(): |
1151 if "@return" not in docstringContext.ssource(): |
1183 if ( |
1152 if ( |
1184 set(return_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} |
1153 set(return_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} |
1185 != set() |
1154 != set() |
1186 ): |
1155 ): |
1187 self.__error(docstringContext.end(), 0, "D-234r") |
1156 self.addError(docstringContext.end(), 0, "D-234r") |
1188 else: |
1157 else: |
1189 if ( |
1158 if ( |
1190 set(return_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} |
1159 set(return_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} |
1191 == set() |
1160 == set() |
1192 ): |
1161 ): |
1193 self.__error(docstringContext.end(), 0, "D-235r") |
1162 self.addError(docstringContext.end(), 0, "D-235r") |
1194 |
1163 |
1195 def __checkEricYield(self, docstringContext, context): |
1164 def __checkEricYield(self, docstringContext, context): |
1196 """ |
1165 """ |
1197 Private method to check, that docstrings contain an @yield line |
1166 Private method to check, that docstrings contain an @yield line |
1198 if they return anything and don't otherwise. |
1167 if they return anything and don't otherwise. |
1209 yield_ = [ |
1178 yield_ = [ |
1210 tokens[i + 1][0] for i, token in enumerate(tokens) if token[1] == "yield" |
1179 tokens[i + 1][0] for i, token in enumerate(tokens) if token[1] == "yield" |
1211 ] |
1180 ] |
1212 if "@yield" not in docstringContext.ssource(): |
1181 if "@yield" not in docstringContext.ssource(): |
1213 if set(yield_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} != set(): |
1182 if set(yield_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} != set(): |
1214 self.__error(docstringContext.end(), 0, "D-234y") |
1183 self.addError(docstringContext.end(), 0, "D-234y") |
1215 else: |
1184 else: |
1216 if set(yield_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} == set(): |
1185 if set(yield_) - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} == set(): |
1217 self.__error(docstringContext.end(), 0, "D-235y") |
1186 self.addError(docstringContext.end(), 0, "D-235y") |
1218 |
1187 |
1219 def __checkEricFunctionArguments(self, docstringContext, context): |
1188 def __checkEricFunctionArguments(self, docstringContext, context): |
1220 """ |
1189 """ |
1221 Private method to check, that docstrings contain an @param and/or |
1190 Private method to check, that docstrings contain an @param and/or |
1222 @keyparam line for each argument. |
1191 @keyparam line for each argument. |
1251 if line.lstrip().startswith("@") |
1220 if line.lstrip().startswith("@") |
1252 ) |
1221 ) |
1253 if tagstring.count("@param") + tagstring.count("@keyparam") < len( |
1222 if tagstring.count("@param") + tagstring.count("@keyparam") < len( |
1254 argNames + kwNames |
1223 argNames + kwNames |
1255 ): |
1224 ): |
1256 self.__error(docstringContext.end(), 0, "D-236") |
1225 self.addError(docstringContext.end(), 0, "D-236") |
1257 elif tagstring.count("@param") + tagstring.count("@keyparam") > len( |
1226 elif tagstring.count("@param") + tagstring.count("@keyparam") > len( |
1258 argNames + kwNames |
1227 argNames + kwNames |
1259 ): |
1228 ): |
1260 self.__error(docstringContext.end(), 0, "D-237") |
1229 self.addError(docstringContext.end(), 0, "D-237") |
1261 else: |
1230 else: |
1262 # extract @param and @keyparam from docstring |
1231 # extract @param and @keyparam from docstring |
1263 args = [] |
1232 args = [] |
1264 kwargs = [] |
1233 kwargs = [] |
1265 for line in docstringContext.source(): |
1234 for line in docstringContext.source(): |
1272 args.append(name.lstrip("*")) |
1241 args.append(name.lstrip("*")) |
1273 |
1242 |
1274 # do the checks |
1243 # do the checks |
1275 for name in kwNames: |
1244 for name in kwNames: |
1276 if name not in kwargs: |
1245 if name not in kwargs: |
1277 self.__error(docstringContext.end(), 0, "D-238") |
1246 self.addError(docstringContext.end(), 0, "D-238") |
1278 return |
1247 return |
1279 if argNames + kwNames != args: |
1248 if argNames + kwNames != args: |
1280 self.__error(docstringContext.end(), 0, "D-239") |
1249 self.addError(docstringContext.end(), 0, "D-239") |
1281 |
1250 |
1282 def __checkEricException(self, docstringContext, context): |
1251 def __checkEricException(self, docstringContext, context): |
1283 """ |
1252 """ |
1284 Private method to check, that docstrings contain an @exception line |
1253 Private method to check, that docstrings contain an @exception line |
1285 if they raise an exception and don't otherwise. |
1254 if they raise an exception and don't otherwise. |
1315 "@exception" not in docstringContext.ssource() |
1284 "@exception" not in docstringContext.ssource() |
1316 and "@throws" not in docstringContext.ssource() |
1285 and "@throws" not in docstringContext.ssource() |
1317 and "@raise" not in docstringContext.ssource() |
1286 and "@raise" not in docstringContext.ssource() |
1318 ): |
1287 ): |
1319 if exceptions - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} != set(): |
1288 if exceptions - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} != set(): |
1320 self.__error(docstringContext.end(), 0, "D-250") |
1289 self.addError(docstringContext.end(), 0, "D-250") |
1321 else: |
1290 else: |
1322 if exceptions - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} == set(): |
1291 if exceptions - {tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE} == set(): |
1323 self.__error(docstringContext.end(), 0, "D-251") |
1292 self.addError(docstringContext.end(), 0, "D-251") |
1324 else: |
1293 else: |
1325 # step 1: extract documented exceptions |
1294 # step 1: extract documented exceptions |
1326 documentedExceptions = set() |
1295 documentedExceptions = set() |
1327 for line in docstringContext.source(): |
1296 for line in docstringContext.source(): |
1328 line = line.strip() |
1297 line = line.strip() |
1332 documentedExceptions.add(exceptionTokens[1]) |
1301 documentedExceptions.add(exceptionTokens[1]) |
1333 |
1302 |
1334 # step 2: report undocumented exceptions |
1303 # step 2: report undocumented exceptions |
1335 for exception in raisedExceptions: |
1304 for exception in raisedExceptions: |
1336 if exception not in documentedExceptions: |
1305 if exception not in documentedExceptions: |
1337 self.__error(docstringContext.end(), 0, "D-252", exception) |
1306 self.addError(docstringContext.end(), 0, "D-252", exception) |
1338 |
1307 |
1339 # step 3: report undefined signals |
1308 # step 3: report undefined signals |
1340 for exception in documentedExceptions: |
1309 for exception in documentedExceptions: |
1341 if exception not in raisedExceptions: |
1310 if exception not in raisedExceptions: |
1342 self.__error(docstringContext.end(), 0, "D-253", exception) |
1311 self.addError(docstringContext.end(), 0, "D-253", exception) |
1343 |
1312 |
1344 def __checkEricSignal(self, docstringContext, context): |
1313 def __checkEricSignal(self, docstringContext, context): |
1345 """ |
1314 """ |
1346 Private method to check, that docstrings contain an @signal line |
1315 Private method to check, that docstrings contain an @signal line |
1347 if they define signals and don't otherwise. |
1316 if they define signals and don't otherwise. |
1366 definedSignals.add(tokens[i - 4][1]) |
1335 definedSignals.add(tokens[i - 4][1]) |
1367 elif tokens[i - 1][1] == "=": |
1336 elif tokens[i - 1][1] == "=": |
1368 definedSignals.add(tokens[i - 2][1]) |
1337 definedSignals.add(tokens[i - 2][1]) |
1369 |
1338 |
1370 if "@signal" not in docstringContext.ssource() and definedSignals: |
1339 if "@signal" not in docstringContext.ssource() and definedSignals: |
1371 self.__error(docstringContext.end(), 0, "D-260") |
1340 self.addError(docstringContext.end(), 0, "D-260") |
1372 elif "@signal" in docstringContext.ssource(): |
1341 elif "@signal" in docstringContext.ssource(): |
1373 if not definedSignals: |
1342 if not definedSignals: |
1374 self.__error(docstringContext.end(), 0, "D-261") |
1343 self.addError(docstringContext.end(), 0, "D-261") |
1375 else: |
1344 else: |
1376 # step 1: extract documented signals |
1345 # step 1: extract documented signals |
1377 documentedSignals = set() |
1346 documentedSignals = set() |
1378 for line in docstringContext.source(): |
1347 for line in docstringContext.source(): |
1379 line = line.strip() |
1348 line = line.strip() |
1386 documentedSignals.add(signal) |
1355 documentedSignals.add(signal) |
1387 |
1356 |
1388 # step 2: report undocumented signals |
1357 # step 2: report undocumented signals |
1389 for signal in definedSignals: |
1358 for signal in definedSignals: |
1390 if signal not in documentedSignals: |
1359 if signal not in documentedSignals: |
1391 self.__error(docstringContext.end(), 0, "D-262", signal) |
1360 self.addError(docstringContext.end(), 0, "D-262", signal) |
1392 |
1361 |
1393 # step 3: report undefined signals |
1362 # step 3: report undefined signals |
1394 for signal in documentedSignals: |
1363 for signal in documentedSignals: |
1395 if signal not in definedSignals: |
1364 if signal not in definedSignals: |
1396 self.__error(docstringContext.end(), 0, "D-263", signal) |
1365 self.addError(docstringContext.end(), 0, "D-263", signal) |
1397 |
1366 |
1398 def __checkEricBlankAfterSummary(self, docstringContext, _context): |
1367 def __checkEricBlankAfterSummary(self, docstringContext, _context): |
1399 """ |
1368 """ |
1400 Private method to check, that docstring summaries are followed |
1369 Private method to check, that docstring summaries are followed |
1401 by a blank line. |
1370 by a blank line. |
1416 summaryLines, lineNumber = self.__getSummaryLines(docstringContext) |
1385 summaryLines, lineNumber = self.__getSummaryLines(docstringContext) |
1417 if ( |
1386 if ( |
1418 len(docstrings) - 2 > lineNumber + len(summaryLines) - 1 |
1387 len(docstrings) - 2 > lineNumber + len(summaryLines) - 1 |
1419 and docstrings[lineNumber + len(summaryLines)].strip() |
1388 and docstrings[lineNumber + len(summaryLines)].strip() |
1420 ): |
1389 ): |
1421 self.__error(docstringContext.start() + lineNumber, 0, "D-246") |
1390 self.addError(docstringContext.start() + lineNumber, 0, "D-246") |
1422 |
1391 |
1423 def __checkEricNoBlankBeforeAndAfterClassOrFunction( |
1392 def __checkEricNoBlankBeforeAndAfterClassOrFunction( |
1424 self, docstringContext, context |
1393 self, docstringContext, context |
1425 ): |
1394 ): |
1426 """ |
1395 """ |
1458 if cti >= len(contextLines) - 1: |
1427 if cti >= len(contextLines) - 1: |
1459 return |
1428 return |
1460 |
1429 |
1461 if isClassContext: |
1430 if isClassContext: |
1462 if not contextLines[start - 1].strip(): |
1431 if not contextLines[start - 1].strip(): |
1463 self.__error(docstringContext.start(), 0, "D-242") |
1432 self.addError(docstringContext.start(), 0, "D-242") |
1464 if not contextLines[end + 1].strip() and self.__docType == "eric": |
1433 if not contextLines[end + 1].strip() and self.__docType == "eric": |
1465 self.__error(docstringContext.end(), 0, "D-243") |
1434 self.addError(docstringContext.end(), 0, "D-243") |
1466 elif contextLines[end + 1].strip() and self.__docType == "eric_black": |
1435 elif contextLines[end + 1].strip() and self.__docType == "eric_black": |
1467 self.__error(docstringContext.end(), 0, "D-143") |
1436 self.addError(docstringContext.end(), 0, "D-143") |
1468 else: |
1437 else: |
1469 if not contextLines[start - 1].strip(): |
1438 if not contextLines[start - 1].strip(): |
1470 self.__error(docstringContext.start(), 0, "D-244") |
1439 self.addError(docstringContext.start(), 0, "D-244") |
1471 if not contextLines[end + 1].strip(): |
1440 if not contextLines[end + 1].strip(): |
1472 if ( |
1441 if ( |
1473 self.__docType == "eric_black" |
1442 self.__docType == "eric_black" |
1474 and len(contextLines) > end + 2 |
1443 and len(contextLines) > end + 2 |
1475 and contextLines[end + 2].strip().startswith("def ") |
1444 and contextLines[end + 2].strip().startswith("def ") |
1476 ): |
1445 ): |
1477 return |
1446 return |
1478 |
1447 |
1479 self.__error(docstringContext.end(), 0, "D-245") |
1448 self.addError(docstringContext.end(), 0, "D-245") |
1480 |
1449 |
1481 def __checkEricNBlankAfterLastParagraph(self, docstringContext, _context): |
1450 def __checkEricNBlankAfterLastParagraph(self, docstringContext, _context): |
1482 """ |
1451 """ |
1483 Private method to check, that the last paragraph of docstrings is |
1452 Private method to check, that the last paragraph of docstrings is |
1484 not followed by a blank line. |
1453 not followed by a blank line. |
1495 if len(docstrings) <= 3: |
1464 if len(docstrings) <= 3: |
1496 # correct/invalid one-liner |
1465 # correct/invalid one-liner |
1497 return |
1466 return |
1498 |
1467 |
1499 if not docstrings[-2].strip(): |
1468 if not docstrings[-2].strip(): |
1500 self.__error(docstringContext.end(), 0, "D-247") |
1469 self.addError(docstringContext.end(), 0, "D-247") |
1501 |
1470 |
1502 def __checkEricSummary(self, docstringContext, context): |
1471 def __checkEricSummary(self, docstringContext, context): |
1503 """ |
1472 """ |
1504 Private method to check, that method docstring summaries start with |
1473 Private method to check, that method docstring summaries start with |
1505 specific words. |
1474 specific words. |
1520 context.source()[0].lstrip().split()[1].split("(", 1) |
1489 context.source()[0].lstrip().split()[1].split("(", 1) |
1521 ) |
1490 ) |
1522 firstWord = summary.strip().split(None, 1)[0].lower() |
1491 firstWord = summary.strip().split(None, 1)[0].lower() |
1523 if functionName == "__init__": |
1492 if functionName == "__init__": |
1524 if firstWord != "constructor": |
1493 if firstWord != "constructor": |
1525 self.__error( |
1494 self.addError( |
1526 docstringContext.start() + lineNumber, 0, "D-232", "constructor" |
1495 docstringContext.start() + lineNumber, 0, "D-232", "constructor" |
1527 ) |
1496 ) |
1528 elif functionName.startswith("__") and functionName.endswith("__"): |
1497 elif functionName.startswith("__") and functionName.endswith("__"): |
1529 if firstWord != "special": |
1498 if firstWord != "special": |
1530 self.__error( |
1499 self.addError( |
1531 docstringContext.start() + lineNumber, 0, "D-232", "special" |
1500 docstringContext.start() + lineNumber, 0, "D-232", "special" |
1532 ) |
1501 ) |
1533 elif context.special() == "staticmethod": |
1502 elif context.special() == "staticmethod": |
1534 secondWord = summary.strip().split(None, 2)[1].lower() |
1503 secondWord = summary.strip().split(None, 2)[1].lower() |
1535 if firstWord != "static" and secondWord != "static": |
1504 if firstWord != "static" and secondWord != "static": |
1536 self.__error( |
1505 self.addError( |
1537 docstringContext.start() + lineNumber, 0, "D-232", "static" |
1506 docstringContext.start() + lineNumber, 0, "D-232", "static" |
1538 ) |
1507 ) |
1539 elif secondWord == "static": |
1508 elif secondWord == "static": |
1540 if functionName.startswith(("__", "on_")): |
1509 if functionName.startswith(("__", "on_")): |
1541 if firstWord != "private": |
1510 if firstWord != "private": |
1542 self.__error( |
1511 self.addError( |
1543 docstringContext.start() + lineNumber, |
1512 docstringContext.start() + lineNumber, |
1544 0, |
1513 0, |
1545 "D-232", |
1514 "D-232", |
1546 "private static", |
1515 "private static", |
1547 ) |
1516 ) |
1548 elif functionName.startswith("_") or functionName.endswith("Event"): |
1517 elif functionName.startswith("_") or functionName.endswith("Event"): |
1549 if firstWord != "protected": |
1518 if firstWord != "protected": |
1550 self.__error( |
1519 self.addError( |
1551 docstringContext.start() + lineNumber, |
1520 docstringContext.start() + lineNumber, |
1552 0, |
1521 0, |
1553 "D-232", |
1522 "D-232", |
1554 "protected static", |
1523 "protected static", |
1555 ) |
1524 ) |
1556 else: |
1525 else: |
1557 if firstWord != "public": |
1526 if firstWord != "public": |
1558 self.__error( |
1527 self.addError( |
1559 docstringContext.start() + lineNumber, |
1528 docstringContext.start() + lineNumber, |
1560 0, |
1529 0, |
1561 "D-232", |
1530 "D-232", |
1562 "public static", |
1531 "public static", |
1563 ) |
1532 ) |
1565 arguments.startswith(("cls,", "cls)")) |
1534 arguments.startswith(("cls,", "cls)")) |
1566 or context.special() == "classmethod" |
1535 or context.special() == "classmethod" |
1567 ): |
1536 ): |
1568 secondWord = summary.strip().split(None, 2)[1].lower() |
1537 secondWord = summary.strip().split(None, 2)[1].lower() |
1569 if firstWord != "class" and secondWord != "class": |
1538 if firstWord != "class" and secondWord != "class": |
1570 self.__error( |
1539 self.addError( |
1571 docstringContext.start() + lineNumber, 0, "D-232", "class" |
1540 docstringContext.start() + lineNumber, 0, "D-232", "class" |
1572 ) |
1541 ) |
1573 elif secondWord == "class": |
1542 elif secondWord == "class": |
1574 if functionName.startswith(("__", "on_")): |
1543 if functionName.startswith(("__", "on_")): |
1575 if firstWord != "private": |
1544 if firstWord != "private": |
1576 self.__error( |
1545 self.addError( |
1577 docstringContext.start() + lineNumber, |
1546 docstringContext.start() + lineNumber, |
1578 0, |
1547 0, |
1579 "D-232", |
1548 "D-232", |
1580 "private class", |
1549 "private class", |
1581 ) |
1550 ) |
1582 elif functionName.startswith("_") or functionName.endswith("Event"): |
1551 elif functionName.startswith("_") or functionName.endswith("Event"): |
1583 if firstWord != "protected": |
1552 if firstWord != "protected": |
1584 self.__error( |
1553 self.addError( |
1585 docstringContext.start() + lineNumber, |
1554 docstringContext.start() + lineNumber, |
1586 0, |
1555 0, |
1587 "D-232", |
1556 "D-232", |
1588 "protected class", |
1557 "protected class", |
1589 ) |
1558 ) |
1590 else: |
1559 else: |
1591 if firstWord != "public": |
1560 if firstWord != "public": |
1592 self.__error( |
1561 self.addError( |
1593 docstringContext.start() + lineNumber, |
1562 docstringContext.start() + lineNumber, |
1594 0, |
1563 0, |
1595 "D-232", |
1564 "D-232", |
1596 "public class", |
1565 "public class", |
1597 ) |
1566 ) |
1598 elif functionName.startswith(("__", "on_")): |
1567 elif functionName.startswith(("__", "on_")): |
1599 if firstWord != "private": |
1568 if firstWord != "private": |
1600 self.__error( |
1569 self.addError( |
1601 docstringContext.start() + lineNumber, 0, "D-232", "private" |
1570 docstringContext.start() + lineNumber, 0, "D-232", "private" |
1602 ) |
1571 ) |
1603 elif functionName.startswith("_") or functionName.endswith("Event"): |
1572 elif functionName.startswith("_") or functionName.endswith("Event"): |
1604 if firstWord != "protected": |
1573 if firstWord != "protected": |
1605 self.__error( |
1574 self.addError( |
1606 docstringContext.start() + lineNumber, 0, "D-232", "protected" |
1575 docstringContext.start() + lineNumber, 0, "D-232", "protected" |
1607 ) |
1576 ) |
1608 else: |
1577 else: |
1609 if firstWord != "public": |
1578 if firstWord != "public": |
1610 self.__error( |
1579 self.addError( |
1611 docstringContext.start() + lineNumber, 0, "D-232", "public" |
1580 docstringContext.start() + lineNumber, 0, "D-232", "public" |
1612 ) |
1581 ) |
1613 |
1582 |
1614 def __checkEricDocumentationSequence( |
1583 def __checkEricDocumentationSequence( |
1615 self, |
1584 self, |
1654 docToken2, _ = docTokens[index + 1] |
1623 docToken2, _ = docTokens[index + 1] |
1655 except IndexError: |
1624 except IndexError: |
1656 docToken2 = "" |
1625 docToken2 = "" |
1657 |
1626 |
1658 if docToken in ("@param", "@keyparam") and docToken2 != "@type": |
1627 if docToken in ("@param", "@keyparam") and docToken2 != "@type": |
1659 self.__error( |
1628 self.addError( |
1660 docstringContext.start() + lineno, 0, "D-270", docToken, "@type" |
1629 docstringContext.start() + lineno, 0, "D-270", docToken, "@type" |
1661 ) |
1630 ) |
1662 elif docToken == "@return" and docToken2 != "@rtype": |
1631 elif docToken == "@return" and docToken2 != "@rtype": |
1663 self.__error( |
1632 self.addError( |
1664 docstringContext.start() + lineno, 0, "D-270", docToken, "@rtype" |
1633 docstringContext.start() + lineno, 0, "D-270", docToken, "@rtype" |
1665 ) |
1634 ) |
1666 elif docToken == "@yield" and docToken2 != "@ytype": |
1635 elif docToken == "@yield" and docToken2 != "@ytype": |
1667 self.__error( |
1636 self.addError( |
1668 docstringContext.start() + lineno, 0, "D-270", docToken, "@ytype" |
1637 docstringContext.start() + lineno, 0, "D-270", docToken, "@ytype" |
1669 ) |
1638 ) |
1670 |
1639 |
1671 def __checkEricDocumentationDeprecatedTags( |
1640 def __checkEricDocumentationDeprecatedTags( |
1672 self, |
1641 self, |
1696 strippedLine = line.lstrip() |
1665 strippedLine = line.lstrip() |
1697 if strippedLine.startswith("@"): |
1666 if strippedLine.startswith("@"): |
1698 # it is a tag line |
1667 # it is a tag line |
1699 tag = strippedLine.split(None, 1)[0] |
1668 tag = strippedLine.split(None, 1)[0] |
1700 with contextlib.suppress(KeyError): |
1669 with contextlib.suppress(KeyError): |
1701 self.__error( |
1670 self.addError( |
1702 docstringContext.start() + lineno, |
1671 docstringContext.start() + lineno, |
1703 0, |
1672 0, |
1704 "D-272", |
1673 "D-272", |
1705 tag, |
1674 tag, |
1706 deprecationsList[tag], |
1675 deprecationsList[tag], |
1735 strippedLine = line.lstrip() |
1704 strippedLine = line.lstrip() |
1736 if strippedLine.startswith("@"): |
1705 if strippedLine.startswith("@"): |
1737 tag = strippedLine.split(None, 1)[0] |
1706 tag = strippedLine.split(None, 1)[0] |
1738 currentIndentation = len(line) - len(strippedLine) |
1707 currentIndentation = len(line) - len(strippedLine) |
1739 if currentIndentation != indentationLength: |
1708 if currentIndentation != indentationLength: |
1740 self.__error(docstringContext.start() + lineno, 0, "D-273", tag) |
1709 self.addError(docstringContext.start() + lineno, 0, "D-273", tag) |