Plugins/CheckerPlugins/CodeStyleChecker/pep8.py

branch
Py2 comp.
changeset 3456
96232974dcdb
parent 3178
f25fc1364c88
parent 3413
5e63f809732a
child 3484
645c12de6b0c
equal deleted inserted replaced
3178:f25fc1364c88 3456:96232974dcdb
46 600 deprecation 46 600 deprecation
47 700 statements 47 700 statements
48 900 syntax error 48 900 syntax error
49 """ 49 """
50 50
51 from __future__ import unicode_literals
52
53 # 51 #
54 # This is a modified version to make the original pep8.py better suitable 52 # This is a modified version to make the original pep8.py better suitable
55 # for being called from within the eric5 IDE. The modifications are as 53 # for being called from within the eric5 IDE. The modifications are as
56 # follows: 54 # follows:
57 # 55 #
76 from configparser import RawConfigParser 74 from configparser import RawConfigParser
77 from io import TextIOWrapper 75 from io import TextIOWrapper
78 except ImportError: 76 except ImportError:
79 from ConfigParser import RawConfigParser # __IGNORE_WARNING__ 77 from ConfigParser import RawConfigParser # __IGNORE_WARNING__
80 78
81 from PyQt4.QtCore import QCoreApplication, QT_TRANSLATE_NOOP
82
83 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__' 79 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__'
84 DEFAULT_IGNORE = 'E123,E226,E24' 80 DEFAULT_IGNORE = 'E123,E226,E24'
85 if sys.platform == 'win32': 81 if sys.platform == 'win32':
86 DEFAULT_CONFIG = os.path.expanduser(r'~\.pep8') 82 DEFAULT_CONFIG = os.path.expanduser(r'~\.pep8')
87 else: 83 else:
128 # a comment which is on a line by itself. 124 # a comment which is on a line by itself.
129 COMMENT_WITH_NL = tokenize.generate_tokens(['#\n'].pop).send(None)[1] == '#\n' 125 COMMENT_WITH_NL = tokenize.generate_tokens(['#\n'].pop).send(None)[1] == '#\n'
130 126
131 127
132 ############################################################################## 128 ##############################################################################
133 # Helper functions for translated and formatted messages
134 ##############################################################################
135
136
137 pep8_messages = {
138 "E101": QT_TRANSLATE_NOOP("pep8",
139 "indentation contains mixed spaces and tabs"),
140 "E111": QT_TRANSLATE_NOOP("pep8",
141 "indentation is not a multiple of four"),
142 "E112": QT_TRANSLATE_NOOP("pep8",
143 "expected an indented block"),
144 "E113": QT_TRANSLATE_NOOP("pep8",
145 "unexpected indentation"),
146 "E121": QT_TRANSLATE_NOOP("pep8",
147 "continuation line indentation is not a multiple of four"),
148 "E122": QT_TRANSLATE_NOOP("pep8",
149 "continuation line missing indentation or outdented"),
150 "E123": QT_TRANSLATE_NOOP("pep8",
151 "closing bracket does not match indentation of opening"
152 " bracket's line"),
153 "E124": QT_TRANSLATE_NOOP("pep8",
154 "closing bracket does not match visual indentation"),
155 "E125": QT_TRANSLATE_NOOP("pep8",
156 "continuation line does not distinguish itself from next"
157 " logical line"),
158 "E126": QT_TRANSLATE_NOOP("pep8",
159 "continuation line over-indented for hanging indent"),
160 "E127": QT_TRANSLATE_NOOP("pep8",
161 "continuation line over-indented for visual indent"),
162 "E128": QT_TRANSLATE_NOOP("pep8",
163 "continuation line under-indented for visual indent"),
164 "E133": QT_TRANSLATE_NOOP("pep8",
165 "closing bracket is missing indentation"),
166 "W191": QT_TRANSLATE_NOOP("pep8",
167 "indentation contains tabs"),
168 "E201": QT_TRANSLATE_NOOP("pep8",
169 "whitespace after '{0}'"),
170 "E202": QT_TRANSLATE_NOOP("pep8",
171 "whitespace before '{0}'"),
172 "E203": QT_TRANSLATE_NOOP("pep8",
173 "whitespace before '{0}'"),
174 "E211": QT_TRANSLATE_NOOP("pep8",
175 "whitespace before '{0}'"),
176 "E221": QT_TRANSLATE_NOOP("pep8",
177 "multiple spaces before operator"),
178 "E222": QT_TRANSLATE_NOOP("pep8",
179 "multiple spaces after operator"),
180 "E223": QT_TRANSLATE_NOOP("pep8",
181 "tab before operator"),
182 "E224": QT_TRANSLATE_NOOP("pep8",
183 "tab after operator"),
184 "E225": QT_TRANSLATE_NOOP("pep8",
185 "missing whitespace around operator"),
186 "E226": QT_TRANSLATE_NOOP("pep8",
187 "missing whitespace around arithmetic operator"),
188 "E227": QT_TRANSLATE_NOOP("pep8",
189 "missing whitespace around bitwise or shift operator"),
190 "E228": QT_TRANSLATE_NOOP("pep8",
191 "missing whitespace around modulo operator"),
192 "E231": QT_TRANSLATE_NOOP("pep8",
193 "missing whitespace after '{0}'"),
194 "E241": QT_TRANSLATE_NOOP("pep8",
195 "multiple spaces after '{0}'"),
196 "E242": QT_TRANSLATE_NOOP("pep8",
197 "tab after '{0}'"),
198 "E251": QT_TRANSLATE_NOOP("pep8",
199 "unexpected spaces around keyword / parameter equals"),
200 "E261": QT_TRANSLATE_NOOP("pep8",
201 "at least two spaces before inline comment"),
202 "E262": QT_TRANSLATE_NOOP("pep8",
203 "inline comment should start with '# '"),
204 "E271": QT_TRANSLATE_NOOP("pep8",
205 "multiple spaces after keyword"),
206 "E272": QT_TRANSLATE_NOOP("pep8",
207 "multiple spaces before keyword"),
208 "E273": QT_TRANSLATE_NOOP("pep8",
209 "tab after keyword"),
210 "E274": QT_TRANSLATE_NOOP("pep8",
211 "tab before keyword"),
212 "W291": QT_TRANSLATE_NOOP("pep8",
213 "trailing whitespace"),
214 "W292": QT_TRANSLATE_NOOP("pep8",
215 "no newline at end of file"),
216 "W293": QT_TRANSLATE_NOOP("pep8",
217 "blank line contains whitespace"),
218 "E301": QT_TRANSLATE_NOOP("pep8",
219 "expected 1 blank line, found 0"),
220 "E302": QT_TRANSLATE_NOOP("pep8",
221 "expected 2 blank lines, found {0}"),
222 "E303": QT_TRANSLATE_NOOP("pep8",
223 "too many blank lines ({0})"),
224 "E304": QT_TRANSLATE_NOOP("pep8",
225 "blank lines found after function decorator"),
226 "W391": QT_TRANSLATE_NOOP("pep8",
227 "blank line at end of file"),
228 "E401": QT_TRANSLATE_NOOP("pep8",
229 "multiple imports on one line"),
230 "E501": QT_TRANSLATE_NOOP("pep8",
231 "line too long ({0} > {1} characters)"),
232 "E502": QT_TRANSLATE_NOOP("pep8",
233 "the backslash is redundant between brackets"),
234 "W601": QT_TRANSLATE_NOOP("pep8",
235 ".has_key() is deprecated, use 'in'"),
236 "W602": QT_TRANSLATE_NOOP("pep8",
237 "deprecated form of raising exception"),
238 "W603": QT_TRANSLATE_NOOP("pep8",
239 "'<>' is deprecated, use '!='"),
240 "W604": QT_TRANSLATE_NOOP("pep8",
241 "backticks are deprecated, use 'repr()'"),
242 "E701": QT_TRANSLATE_NOOP("pep8",
243 "multiple statements on one line (colon)"),
244 "E702": QT_TRANSLATE_NOOP("pep8",
245 "multiple statements on one line (semicolon)"),
246 "E703": QT_TRANSLATE_NOOP("pep8",
247 "statement ends with a semicolon"),
248 "E711": QT_TRANSLATE_NOOP("pep8",
249 "comparison to {0} should be {1}"),
250 "E712": QT_TRANSLATE_NOOP("pep8",
251 "comparison to {0} should be {1}"),
252 "E721": QT_TRANSLATE_NOOP("pep8",
253 "do not compare types, use 'isinstance()'"),
254 "E901": QT_TRANSLATE_NOOP("pep8",
255 "{0}: {1}"),
256 }
257
258 pep8_messages_sample_args = {
259 "E201": ["([{"],
260 "E202": ["}])"],
261 "E203": [",;:"],
262 "E211": ["(["],
263 "E231": [",;:"],
264 "E241": [",;:"],
265 "E242": [",;:"],
266 "E302": [1],
267 "E303": [3],
268 "E501": [85, 79],
269 "E711": ["None", "'if cond is None:'"],
270 "E712": ["True", "'if cond is True:' or 'if cond:'"],
271 "E901": ["SyntaxError", "Invalid Syntax"],
272 }
273
274
275 def getMessage(code, *args):
276 """
277 Function to get a translated and formatted message for a given code.
278
279 @param code message code (string)
280 @param args arguments for a formatted message (list)
281 @return translated and formatted message (string)
282 """
283 if code in pep8_messages:
284 return code + " " + QCoreApplication.translate("pep8",
285 pep8_messages[code]).format(*args)
286 else:
287 return code + " " + QCoreApplication.translate("pep8",
288 "no message for this code defined")
289
290 ##############################################################################
291 # Plugins (check functions) for physical lines 129 # Plugins (check functions) for physical lines
292 ############################################################################## 130 ##############################################################################
293 131
294 132
295 def tabs_or_spaces(physical_line, indent_char): 133 def tabs_or_spaces(physical_line, indent_char):
394 if length > max_line_length and not noqa(line): 232 if length > max_line_length and not noqa(line):
395 if hasattr(line, 'decode'): # Python 2 233 if hasattr(line, 'decode'): # Python 2
396 # The line could contain multi-byte characters 234 # The line could contain multi-byte characters
397 try: 235 try:
398 length = len(line.decode('utf-8')) 236 length = len(line.decode('utf-8'))
399 except (UnicodeDecodeError, UnicodeEncodeError): 237 except UnicodeError:
400 pass 238 pass
401 if length > max_line_length: 239 if length > max_line_length:
402 return max_line_length, "E501", length, max_line_length 240 return max_line_length, "E501", length, max_line_length
403 241
404 242
779 617
780 if '\t' in after: 618 if '\t' in after:
781 yield match.start(2), "E224" 619 yield match.start(2), "E224"
782 elif len(after) > 1: 620 elif len(after) > 1:
783 yield match.start(2), "E222" 621 yield match.start(2), "E222"
622
784 623
785 def missing_whitespace_around_operator(logical_line, tokens): 624 def missing_whitespace_around_operator(logical_line, tokens):
786 r""" 625 r"""
787 - Always surround these binary operators with a single space on 626 - Always surround these binary operators with a single space on
788 either side: assignment (=), augmented assignment (+=, -= etc.), 627 either side: assignment (=), augmented assignment (+=, -= etc.),
1437 for name, check, argument_names in self._physical_checks: 1276 for name, check, argument_names in self._physical_checks:
1438 result = self.run_check(check, argument_names) 1277 result = self.run_check(check, argument_names)
1439 if result is not None: 1278 if result is not None:
1440 offset, code = result[:2] 1279 offset, code = result[:2]
1441 args = result[2:] 1280 args = result[2:]
1442 self.report_error_args(self.line_number, offset, code, check, 1281 self.report_error_args(
1443 *args) 1282 self.line_number, offset, code, check, *args)
1444 1283
1445 def build_tokens_line(self): 1284 def build_tokens_line(self):
1446 """ 1285 """
1447 Build a logical line from tokens. 1286 Build a logical line from tokens.
1448 """ 1287 """
1505 else: 1344 else:
1506 for token_offset, token in self.mapping: 1345 for token_offset, token in self.mapping:
1507 if offset >= token_offset: 1346 if offset >= token_offset:
1508 orig_number = token[2][0] 1347 orig_number = token[2][0]
1509 orig_offset = (token[2][1] + offset - token_offset) 1348 orig_offset = (token[2][1] + offset - token_offset)
1510 self.report_error_args(orig_number, orig_offset, code, check, 1349 self.report_error_args(
1511 *args) 1350 orig_number, orig_offset, code, check, *args)
1512 self.previous_logical = self.logical_line 1351 self.previous_logical = self.logical_line
1513 1352
1514 def check_ast(self): 1353 def check_ast(self):
1515 try: 1354 try:
1516 tree = compile(''.join(self.lines), '', 'exec', PyCF_ONLY_AST) 1355 tree = compile(''.join(self.lines), '', 'exec', PyCF_ONLY_AST)
1627 return 1466 return
1628 if code in self.counters: 1467 if code in self.counters:
1629 self.counters[code] += 1 1468 self.counters[code] += 1
1630 else: 1469 else:
1631 self.counters[code] = 1 1470 self.counters[code] = 1
1632 self.messages[code] = text[5:] 1471 self.messages[code] = []
1633 # Don't care about expected errors or warnings 1472 # Don't care about expected errors or warnings
1634 if code in self.expected: 1473 if code in self.expected:
1635 return 1474 return
1636 if self.print_filename and not self.file_errors: 1475 if self.print_filename and not self.file_errors:
1637 print(self.filename) 1476 print(self.filename)
1641 1480
1642 def error_args(self, line_number, offset, code, check, *args): 1481 def error_args(self, line_number, offset, code, check, *args):
1643 """Report an error, according to options.""" 1482 """Report an error, according to options."""
1644 if self._ignore_code(code): 1483 if self._ignore_code(code):
1645 return 1484 return
1646 text = getMessage(code, *args)
1647 if code in self.counters: 1485 if code in self.counters:
1648 self.counters[code] += 1 1486 self.counters[code] += 1
1649 else: 1487 else:
1650 self.counters[code] = 1 1488 self.counters[code] = 1
1651 self.messages[code] = text[5:] 1489 self.messages[code] = args
1652 # Don't care about expected errors or warnings 1490 # Don't care about expected errors or warnings
1653 if code in self.expected: 1491 if code in self.expected:
1654 return 1492 return
1655 if self.print_filename and not self.file_errors: 1493 if self.print_filename and not self.file_errors:
1656 print(self.filename) 1494 print(self.filename)
1728 def error_args(self, line_number, offset, code, check, *args): 1566 def error_args(self, line_number, offset, code, check, *args):
1729 """Report an error, according to options.""" 1567 """Report an error, according to options."""
1730 code = super(StandardReport, self).error_args(line_number, offset, 1568 code = super(StandardReport, self).error_args(line_number, offset,
1731 code, check, *args) 1569 code, check, *args)
1732 if code and (self.counters[code] == 1 or self._repeat): 1570 if code and (self.counters[code] == 1 or self._repeat):
1733 text = getMessage(code, *args)
1734 self._deferred_print.append( 1571 self._deferred_print.append(
1735 (line_number, offset, code, text[5:], check.__doc__)) 1572 (line_number, offset, code, args, check.__doc__))
1736 return code 1573 return code
1737 1574
1738 def get_file_results(self): 1575 def get_file_results(self):
1739 """Print the result and return the overall count for this file.""" 1576 """Print the result and return the overall count for this file."""
1740 self._deferred_print.sort() 1577 self._deferred_print.sort()

eric ide

mercurial