Plugins/CheckerPlugins/Pep8/Pep257Checker.py

changeset 2916
a8628dfdfe04
parent 2915
9da653363d07
child 2917
fe82710d02cb
equal deleted inserted replaced
2915:9da653363d07 2916:a8628dfdfe04
105 Codes = [ 105 Codes = [
106 "D101", "D102", "D103", "D104", "D105", 106 "D101", "D102", "D103", "D104", "D105",
107 "D111", "D112", "D113", 107 "D111", "D112", "D113",
108 "D121", "D122", 108 "D121", "D122",
109 "D131", "D132", "D133", "D134", 109 "D131", "D132", "D133", "D134",
110 "D141" 110 "D141", "D142", "D143", "D144", "D145",
111 ] 111 ]
112 112
113 Messages = { 113 Messages = {
114 "D101": QT_TRANSLATE_NOOP( 114 "D101": QT_TRANSLATE_NOOP(
115 "Pep257Checker", "module is missing a docstring"), 115 "Pep257Checker", "module is missing a docstring"),
144 "docstring summary looks like a function's/method's signature"), 144 "docstring summary looks like a function's/method's signature"),
145 "D134": QT_TRANSLATE_NOOP( 145 "D134": QT_TRANSLATE_NOOP(
146 "Pep257Checker", 146 "Pep257Checker",
147 "docstring does not mention the return value type"), 147 "docstring does not mention the return value type"),
148 "D141": QT_TRANSLATE_NOOP( 148 "D141": QT_TRANSLATE_NOOP(
149 "Pep257Checker", "docstring is separated by a blank line"), 149 "Pep257Checker",
150 "function/method docstring is separated by a blank line"),
151 "D142": QT_TRANSLATE_NOOP(
152 "Pep257Checker",
153 "class docstring is not preceded by a blank line"),
154 "D143": QT_TRANSLATE_NOOP(
155 "Pep257Checker",
156 "class docstring is not followed by a blank line"),
157 "D144": QT_TRANSLATE_NOOP(
158 "Pep257Checker",
159 "docstring summary is not followed by a blank line"),
160 "D145": QT_TRANSLATE_NOOP(
161 "Pep257Checker",
162 "last paragraph of docstring is not followed by a blank line"),
150 } 163 }
151 164
152 def __init__(self, source, filename, select, ignore, expected, repeat): 165 def __init__(self, source, filename, select, ignore, expected, repeat,
166 maxLineLength=79):
153 """ 167 """
154 Constructor (according to 'extended' pep8.py API) 168 Constructor (according to 'extended' pep8.py API)
155 169
156 @param source source code to be checked (list of string) 170 @param source source code to be checked (list of string)
157 @param filename name of the source file (string) 171 @param filename name of the source file (string)
158 @param select list of selected codes (list of string) 172 @param select list of selected codes (list of string)
159 @param ignore list of codes to be ignored (list of string) 173 @param ignore list of codes to be ignored (list of string)
160 @param expected list of expected codes (list of string) 174 @param expected list of expected codes (list of string)
161 @param repeat flag indicating to report each occurrence of a code 175 @param repeat flag indicating to report each occurrence of a code
162 (boolean) 176 (boolean)
177 @param maxLineLength allowed line length (integer)
163 """ 178 """
164 self.__select = tuple(select) 179 self.__select = tuple(select)
165 self.__ignore = tuple(ignore) 180 self.__ignore = tuple(ignore)
166 self.__expected = expected[:] 181 self.__expected = expected[:]
167 self.__repeat = repeat 182 self.__repeat = repeat
183 self.__maxLineLength = maxLineLength
168 self.__filename = filename 184 self.__filename = filename
169 self.__source = source[:] 185 self.__source = source[:]
170 self.__isScript = self.__source[0].startswith('#!') 186 self.__isScript = self.__source[0].startswith('#!')
171 187
172 # statistics counters 188 # statistics counters
193 ], 209 ],
194 "functionDocstring": [ 210 "functionDocstring": [
195 ], 211 ],
196 "classDocstring": [ 212 "classDocstring": [
197 (self.__checkClassDocstring, ("D104", "D105")), 213 (self.__checkClassDocstring, ("D104", "D105")),
214 (self.__checkBlankBeforeAndAfterClass, ("D142", "D143")),
198 ], 215 ],
199 "methodDocstring": [ 216 "methodDocstring": [
200 ], 217 ],
201 "defDocstring": [ 218 "defDocstring": [
202 (self.__checkFunctionDocstring, ("D102", "D103")), 219 (self.__checkFunctionDocstring, ("D102", "D103")),
210 (self.__checkBackslashes, ("D112",)), 227 (self.__checkBackslashes, ("D112",)),
211 (self.__checkUnicode, ("D113",)), 228 (self.__checkUnicode, ("D113",)),
212 (self.__checkOneLiner, ("D121",)), 229 (self.__checkOneLiner, ("D121",)),
213 (self.__checkIndent, ("D122",)), 230 (self.__checkIndent, ("D122",)),
214 (self.__checkEndsWithPeriod, ("D131",)), 231 (self.__checkEndsWithPeriod, ("D131",)),
232 (self.__checkBlankAfterSummary, ("D144",)),
233 (self.__checkBlankAfterLastParagraph, ("D145",)),
215 ], 234 ],
216 } 235 }
217 236
218 self.__checkers = {} 237 self.__checkers = {}
219 for key, checkers in self.__checkersWithCodes.items(): 238 for key, checkers in self.__checkersWithCodes.items():
321 340
322 line = (lines[0] 341 line = (lines[0]
323 .replace('r"""', "", 1) 342 .replace('r"""', "", 1)
324 .replace('u"""', "", 1) 343 .replace('u"""', "", 1)
325 .replace('"""', "") 344 .replace('"""', "")
345 .replace("r'''", "", 1)
346 .replace("u'''", "", 1)
347 .replace("'''", "")
326 .strip()) 348 .strip())
327 349
328 if len(lines) == 1 or len(line) > 0: 350 if len(lines) == 1 or len(line) > 0:
329 return line, 0 351 return line, 0
330 return lines[1].strip(), 1
331
332 first_line = lines[0].strip()
333 if len(lines) == 1 or len(first_line) > 0:
334 return first_line, 0
335 return lines[1].strip(), 1 352 return lines[1].strip(), 1
336 353
337 ################################################################## 354 ##################################################################
338 ## Parsing functionality below 355 ## Parsing functionality below
339 ################################################################## 356 ##################################################################
360 377
361 @param context context data to get the docstring from (Pep257Context) 378 @param context context data to get the docstring from (Pep257Context)
362 @return context of extracted docstring (Pep257Context) 379 @return context of extracted docstring (Pep257Context)
363 """ 380 """
364 moduleDocstring = self.__parseModuleDocstring(context.source()) 381 moduleDocstring = self.__parseModuleDocstring(context.source())
365 if what.startswith('module'): 382 if what.startswith('module') or context.contextType() == "module":
366 return moduleDocstring 383 return moduleDocstring
367 if moduleDocstring: 384 if moduleDocstring:
368 return moduleDocstring 385 return moduleDocstring
369 386
370 tokenGenerator = tokenize.generate_tokens( 387 tokenGenerator = tokenize.generate_tokens(
640 657
641 lines = docstringContext.source() 658 lines = docstringContext.source()
642 if len(lines) > 1: 659 if len(lines) > 1:
643 nonEmptyLines = [l for l in lines if l.strip().strip('\'"')] 660 nonEmptyLines = [l for l in lines if l.strip().strip('\'"')]
644 if len(nonEmptyLines) == 1: 661 if len(nonEmptyLines) == 1:
645 self.__error(docstringContext.start(), 0, "D121") 662 modLen = len(context.indent() + '"""' +
663 nonEmptyLines[0].strip() + '"""')
664 if context.contextType() != "module":
665 modLen += 4
666 if modLen <= self.__maxLineLength:
667 self.__error(docstringContext.start(), 0, "D121")
646 668
647 def __checkIndent(self, docstringContext, context): 669 def __checkIndent(self, docstringContext, context):
648 """ 670 """
649 Private method to check, that docstrings are properly indented. 671 Private method to check, that docstrings are properly indented.
650 672
729 if "return" not in docstringContext.ssource().lower(): 751 if "return" not in docstringContext.ssource().lower():
730 tokens = list( 752 tokens = list(
731 tokenize.generate_tokens(StringIO(context.ssource()).readline)) 753 tokenize.generate_tokens(StringIO(context.ssource()).readline))
732 return_ = [tokens[i + 1][0] for i, token in enumerate(tokens) 754 return_ = [tokens[i + 1][0] for i, token in enumerate(tokens)
733 if token[1] == "return"] 755 if token[1] == "return"]
734 if (set(return_) - 756 if (set(return_) -
735 set([tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE]) != 757 set([tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE]) !=
736 set([])): 758 set([])):
737 self.__error(docstringContext.end(), 0, "D134") 759 self.__error(docstringContext.end(), 0, "D134")
738 760
739 def __checkNoBlankLineBefore(self, docstringContext, context): 761 def __checkNoBlankLineBefore(self, docstringContext, context):
742 preceded by a blank line. 764 preceded by a blank line.
743 765
744 @param docstringContext docstring context (Pep257Context) 766 @param docstringContext docstring context (Pep257Context)
745 @param context context of the docstring (Pep257Context) 767 @param context context of the docstring (Pep257Context)
746 """ 768 """
747 if docstringContext is None or self.__isScript: 769 if docstringContext is None:
748 return 770 return
749 771
750 contextLines = context.source() 772 contextLines = context.source()
751 cti = 0 773 cti = 0
752 while not contextLines[cti].strip().startswith( 774 while cti < len(contextLines) and \
753 ('"""', 'r"""', 'u"""')): 775 not contextLines[cti].strip().startswith(
776 ('"""', 'r"""', 'u"""', "'''", "r'''", "u'''")):
754 cti += 1 777 cti += 1
778
779 if cti == len(contextLines):
780 return
781
755 if not contextLines[cti - 1].strip(): 782 if not contextLines[cti - 1].strip():
756 self.__error(docstringContext.start(), 0, "D141") 783 self.__error(docstringContext.start(), 0, "D141")
757 784
758 # D142: check_blank_before_after_class 785 def __checkBlankBeforeAndAfterClass(self, docstringContext, context):
759 ##def check_blank_before_after_class(class_docstring, context, is_script): 786 """
760 ## """Class docstring should have 1 blank line around them. 787 Private method to check, that class docstrings have one
761 ## 788 blank line around them.
762 ## Insert a blank line before and after all docstrings (one-line or 789
763 ## multi-line) that document a class -- generally speaking, the class's 790 @param docstringContext docstring context (Pep257Context)
764 ## methods are separated from each other by a single blank line, and the 791 @param context context of the docstring (Pep257Context)
765 ## docstring needs to be offset from the first method by a blank line; 792 """
766 ## for symmetry, put a blank line between the class header and the 793 if docstringContext is None:
767 ## docstring. 794 return
768 ## 795
769 ## """ 796 contextLines = context.source()
770 ## if not class_docstring: 797 cti = 0
771 ## return 798 while cti < len(contextLines) and \
772 ## before, after = context.split(class_docstring)[:2] 799 not contextLines[cti].strip().startswith(
773 ## before_blanks = [not line.strip() for line in before.split('\n')] 800 ('"""', 'r"""', 'u"""', "'''", "r'''", "u'''")):
774 ## after_blanks = [not line.strip() for line in after.split('\n')] 801 cti += 1
775 ## if before_blanks[-3:] != [False, True, True]: 802
776 ## return True 803 if cti == len(contextLines):
777 ## if not all(after_blanks) and after_blanks[:3] != [True, True, False]: 804 return
778 ## return True 805
779 806 start = cti
780 # D143: check_blank_after_summary 807 if contextLines[cti].strip() in (
781 ##def check_blank_after_summary(docstring, context, is_script): 808 '"""', 'r"""', 'u"""', "'''", "r'''", "u'''"):
782 ## """Blank line missing after one-line summary. 809 # it is a multi line docstring
783 ## 810 cti += 1
784 ## Multi-line docstrings consist of a summary line just like a one-line 811
785 ## docstring, followed by a blank line, followed by a more elaborate 812 while cti < len(contextLines) and \
786 ## description. The summary line may be used by automatic indexing tools; 813 not contextLines[cti].strip().endswith(('"""', "'''")):
787 ## it is important that it fits on one line and is separated from the 814 cti += 1
788 ## rest of the docstring by a blank line. 815 end = cti
789 ## 816
790 ## """ 817 if contextLines[start - 1].strip():
791 ## if not docstring: 818 self.__error(docstringContext.start(), 0, "D142")
792 ## return 819 if contextLines[end + 1].strip():
793 ## lines = eval(docstring).split('\n') 820 self.__error(docstringContext.end(), 0, "D143")
794 ## if len(lines) > 1: 821
795 ## (summary_line, line_number) = get_summary_line_info(docstring) 822 def __checkBlankAfterSummary(self, docstringContext, context):
796 ## if len(lines) <= (line_number+1) or lines[line_number+1].strip() != '': 823 """
797 ## return True 824 Private method to check, that docstring summaries are followed
798 825 by a blank line.
799 # D144: check_blank_after_last_paragraph 826
800 ##def check_blank_after_last_paragraph(docstring, context, is_script): 827 @param docstringContext docstring context (Pep257Context)
801 ## """Multiline docstring should end with 1 blank line. 828 @param context context of the docstring (Pep257Context)
802 ## 829 """
803 ## The BDFL recommends inserting a blank line between the last 830 if docstringContext is None:
804 ## paragraph in a multi-line docstring and its closing quotes, 831 return
805 ## placing the closing quotes on a line by themselves. 832
806 ## 833 docstrings = docstringContext.source()
807 ## """ 834 if len(docstrings) in [1, 3]:
808 ## if (not docstring) or len(eval(docstring).split('\n')) == 1: 835 # correct/invalid one-liner
809 ## return 836 return
810 ## blanks = [not line.strip() for line in eval(docstring).split('\n')] 837
811 ## if blanks[-3:] != [False, True, True]: 838 summary, lineNumber = self.__getSummaryLine(docstringContext)
812 ## return True 839 if docstrings[lineNumber + 1].strip():
840 self.__error(docstringContext.start() + lineNumber, 0, "D144")
841
842 def __checkBlankAfterLastParagraph(self, docstringContext, context):
843 """
844 Private method to check, that docstring summaries are followed
845 by a blank line.
846
847 @param docstringContext docstring context (Pep257Context)
848 @param context context of the docstring (Pep257Context)
849 """
850 if docstringContext is None:
851 return
852
853 docstrings = docstringContext.source()
854 if len(docstrings) in [1, 3]:
855 # correct/invalid one-liner
856 return
857
858 if docstrings[-2].strip():
859 self.__error(docstringContext.end(), 0, "D145")

eric ide

mercurial