Plugins/CheckerPlugins/CodeStyleChecker/pep8.py

changeset 2982
556adfe76ba7
parent 2910
cdc56e9d9f12
child 3004
c4bf32c791d0
equal deleted inserted replaced
2981:0c5205aa7a5a 2982:556adfe76ba7
1 # -*- coding: utf-8 -*-
2
3 #
4 # pep8.py - Check Python source code formatting, according to PEP 8
5 # Copyright (C) 2006-2009 Johann C. Rocholl <johann@rocholl.net>
6 # Copyright (C) 2009-2013 Florent Xicluna <florent.xicluna@gmail.com>
7 #
8 # Permission is hereby granted, free of charge, to any person
9 # obtaining a copy of this software and associated documentation files
10 # (the "Software"), to deal in the Software without restriction,
11 # including without limitation the rights to use, copy, modify, merge,
12 # publish, distribute, sublicense, and/or sell copies of the Software,
13 # and to permit persons to whom the Software is furnished to do so,
14 # subject to the following conditions:
15 #
16 # The above copyright notice and this permission notice shall be
17 # included in all copies or substantial portions of the Software.
18 #
19 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
23 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
24 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
25 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 # SOFTWARE.
27
28 """
29 Check Python source code formatting, according to PEP 8:
30 http://www.python.org/dev/peps/pep-0008/
31
32 For usage and a list of options, try this:
33 $ python pep8.py -h
34
35 This program and its regression test suite live here:
36 http://github.com/jcrocholl/pep8
37
38 Groups of errors and warnings:
39 E errors
40 W warnings
41 100 indentation
42 200 whitespace
43 300 blank lines
44 400 imports
45 500 line length
46 600 deprecation
47 700 statements
48 900 syntax error
49 """
50
51 #
52 # This is a modified version to make the original pep8.py better suitable
53 # for being called from within the eric5 IDE. The modifications are as
54 # follows:
55 #
56 # - made messages translatable via Qt
57 # - added code for eric5 integration
58 #
59 # Copyright (c) 2011 - 2013 Detlev Offenbach <detlev@die-offenbachs.de>
60 #
61
62 __version__ = '1.4.6'
63
64 import os
65 import sys
66 import re
67 import time
68 import inspect
69 import keyword
70 import tokenize
71 from optparse import OptionParser
72 from fnmatch import fnmatch
73 try:
74 from configparser import RawConfigParser
75 from io import TextIOWrapper
76 except ImportError:
77 from ConfigParser import RawConfigParser # __IGNORE_WARNING__
78
79 from PyQt4.QtCore import QCoreApplication, QT_TRANSLATE_NOOP
80
81 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__'
82 DEFAULT_IGNORE = 'E123,E226,E24'
83 if sys.platform == 'win32':
84 DEFAULT_CONFIG = os.path.expanduser(r'~\.pep8')
85 else:
86 DEFAULT_CONFIG = os.path.join(os.getenv('XDG_CONFIG_HOME') or
87 os.path.expanduser('~/.config'), 'pep8')
88 PROJECT_CONFIG = ('setup.cfg', 'tox.ini', '.pep8')
89 TESTSUITE_PATH = os.path.join(os.path.dirname(__file__), 'testsuite')
90 MAX_LINE_LENGTH = 79
91 REPORT_FORMAT = {
92 'default': '%(path)s:%(row)d:%(col)d: %(code)s %(text)s',
93 'pylint': '%(path)s:%(row)d: [%(code)s] %(text)s',
94 }
95
96 PyCF_ONLY_AST = 1024
97 SINGLETONS = frozenset(['False', 'None', 'True'])
98 KEYWORDS = frozenset(keyword.kwlist + ['print']) - SINGLETONS
99 UNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-'])
100 ARITHMETIC_OP = frozenset(['**', '*', '/', '//', '+', '-'])
101 WS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%'])
102 WS_NEEDED_OPERATORS = frozenset([
103 '**=', '*=', '/=', '//=', '+=', '-=', '!=', '<>', '<', '>',
104 '%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '='])
105 WHITESPACE = frozenset(' \t')
106 SKIP_TOKENS = frozenset([tokenize.COMMENT, tokenize.NL, tokenize.NEWLINE,
107 tokenize.INDENT, tokenize.DEDENT])
108 BENCHMARK_KEYS = ['directories', 'files', 'logical lines', 'physical lines']
109
110 INDENT_REGEX = re.compile(r'([ \t]*)')
111 RAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,')
112 RERAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,\s*\w+\s*,\s*\w+')
113 ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b')
114 DOCSTRING_REGEX = re.compile(r'u?r?["\']')
115 EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[[({] | []}),;:]')
116 WHITESPACE_AFTER_COMMA_REGEX = re.compile(r'[,;:]\s*(?: |\t)')
117 COMPARE_SINGLETON_REGEX = re.compile(r'([=!]=)\s*(None|False|True)')
118 COMPARE_TYPE_REGEX = re.compile(r'(?:[=!]=|is(?:\s+not)?)\s*type(?:s.\w+Type'
119 r'|\s*\(\s*([^)]*[^ )])\s*\))')
120 KEYWORD_REGEX = re.compile(r'(\s*)\b(?:%s)\b(\s*)' % r'|'.join(KEYWORDS))
121 OPERATOR_REGEX = re.compile(r'(?:[^,\s])(\s*)(?:[-+*/|!<=>%&^]+)(\s*)')
122 LAMBDA_REGEX = re.compile(r'\blambda\b')
123 HUNK_REGEX = re.compile(r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$')
124
125 # Work around Python < 2.6 behaviour, which does not generate NL after
126 # a comment which is on a line by itself.
127 COMMENT_WITH_NL = tokenize.generate_tokens(['#\n'].pop).send(None)[1] == '#\n'
128
129
130 ##############################################################################
131 # Helper functions for translated and formatted messages
132 ##############################################################################
133
134
135 pep8_messages = {
136 "E101": QT_TRANSLATE_NOOP("pep8",
137 "indentation contains mixed spaces and tabs"),
138 "E111": QT_TRANSLATE_NOOP("pep8",
139 "indentation is not a multiple of four"),
140 "E112": QT_TRANSLATE_NOOP("pep8",
141 "expected an indented block"),
142 "E113": QT_TRANSLATE_NOOP("pep8",
143 "unexpected indentation"),
144 "E121": QT_TRANSLATE_NOOP("pep8",
145 "continuation line indentation is not a multiple of four"),
146 "E122": QT_TRANSLATE_NOOP("pep8",
147 "continuation line missing indentation or outdented"),
148 "E123": QT_TRANSLATE_NOOP("pep8",
149 "closing bracket does not match indentation of opening bracket's line"),
150 "E124": QT_TRANSLATE_NOOP("pep8",
151 "closing bracket does not match visual indentation"),
152 "E125": QT_TRANSLATE_NOOP("pep8",
153 "continuation line does not distinguish itself from next logical line"),
154 "E126": QT_TRANSLATE_NOOP("pep8",
155 "continuation line over-indented for hanging indent"),
156 "E127": QT_TRANSLATE_NOOP("pep8",
157 "continuation line over-indented for visual indent"),
158 "E128": QT_TRANSLATE_NOOP("pep8",
159 "continuation line under-indented for visual indent"),
160 "E133": QT_TRANSLATE_NOOP("pep8",
161 "closing bracket is missing indentation"),
162 "W191": QT_TRANSLATE_NOOP("pep8",
163 "indentation contains tabs"),
164 "E201": QT_TRANSLATE_NOOP("pep8",
165 "whitespace after '{0}'"),
166 "E202": QT_TRANSLATE_NOOP("pep8",
167 "whitespace before '{0}'"),
168 "E203": QT_TRANSLATE_NOOP("pep8",
169 "whitespace before '{0}'"),
170 "E211": QT_TRANSLATE_NOOP("pep8",
171 "whitespace before '{0}'"),
172 "E221": QT_TRANSLATE_NOOP("pep8",
173 "multiple spaces before operator"),
174 "E222": QT_TRANSLATE_NOOP("pep8",
175 "multiple spaces after operator"),
176 "E223": QT_TRANSLATE_NOOP("pep8",
177 "tab before operator"),
178 "E224": QT_TRANSLATE_NOOP("pep8",
179 "tab after operator"),
180 "E225": QT_TRANSLATE_NOOP("pep8",
181 "missing whitespace around operator"),
182 "E226": QT_TRANSLATE_NOOP("pep8",
183 "missing whitespace around arithmetic operator"),
184 "E227": QT_TRANSLATE_NOOP("pep8",
185 "missing whitespace around bitwise or shift operator"),
186 "E228": QT_TRANSLATE_NOOP("pep8",
187 "missing whitespace around modulo operator"),
188 "E231": QT_TRANSLATE_NOOP("pep8",
189 "missing whitespace after '{0}'"),
190 "E241": QT_TRANSLATE_NOOP("pep8",
191 "multiple spaces after '{0}'"),
192 "E242": QT_TRANSLATE_NOOP("pep8",
193 "tab after '{0}'"),
194 "E251": QT_TRANSLATE_NOOP("pep8",
195 "unexpected spaces around keyword / parameter equals"),
196 "E261": QT_TRANSLATE_NOOP("pep8",
197 "at least two spaces before inline comment"),
198 "E262": QT_TRANSLATE_NOOP("pep8",
199 "inline comment should start with '# '"),
200 "E271": QT_TRANSLATE_NOOP("pep8",
201 "multiple spaces after keyword"),
202 "E272": QT_TRANSLATE_NOOP("pep8",
203 "multiple spaces before keyword"),
204 "E273": QT_TRANSLATE_NOOP("pep8",
205 "tab after keyword"),
206 "E274": QT_TRANSLATE_NOOP("pep8",
207 "tab before keyword"),
208 "W291": QT_TRANSLATE_NOOP("pep8",
209 "trailing whitespace"),
210 "W292": QT_TRANSLATE_NOOP("pep8",
211 "no newline at end of file"),
212 "W293": QT_TRANSLATE_NOOP("pep8",
213 "blank line contains whitespace"),
214 "E301": QT_TRANSLATE_NOOP("pep8",
215 "expected 1 blank line, found 0"),
216 "E302": QT_TRANSLATE_NOOP("pep8",
217 "expected 2 blank lines, found {0}"),
218 "E303": QT_TRANSLATE_NOOP("pep8",
219 "too many blank lines ({0})"),
220 "E304": QT_TRANSLATE_NOOP("pep8",
221 "blank lines found after function decorator"),
222 "W391": QT_TRANSLATE_NOOP("pep8",
223 "blank line at end of file"),
224 "E401": QT_TRANSLATE_NOOP("pep8",
225 "multiple imports on one line"),
226 "E501": QT_TRANSLATE_NOOP("pep8",
227 "line too long ({0} > {1} characters)"),
228 "E502": QT_TRANSLATE_NOOP("pep8",
229 "the backslash is redundant between brackets"),
230 "W601": QT_TRANSLATE_NOOP("pep8",
231 ".has_key() is deprecated, use 'in'"),
232 "W602": QT_TRANSLATE_NOOP("pep8",
233 "deprecated form of raising exception"),
234 "W603": QT_TRANSLATE_NOOP("pep8",
235 "'<>' is deprecated, use '!='"),
236 "W604": QT_TRANSLATE_NOOP("pep8",
237 "backticks are deprecated, use 'repr()'"),
238 "E701": QT_TRANSLATE_NOOP("pep8",
239 "multiple statements on one line (colon)"),
240 "E702": QT_TRANSLATE_NOOP("pep8",
241 "multiple statements on one line (semicolon)"),
242 "E703": QT_TRANSLATE_NOOP("pep8",
243 "statement ends with a semicolon"),
244 "E711": QT_TRANSLATE_NOOP("pep8",
245 "comparison to {0} should be {1}"),
246 "E712": QT_TRANSLATE_NOOP("pep8",
247 "comparison to {0} should be {1}"),
248 "E721": QT_TRANSLATE_NOOP("pep8",
249 "do not compare types, use 'isinstance()'"),
250 "E901": QT_TRANSLATE_NOOP("pep8",
251 "{0}: {1}"),
252 }
253
254 pep8_messages_sample_args = {
255 "E201": ["([{"],
256 "E202": ["}])"],
257 "E203": [",;:"],
258 "E211": ["(["],
259 "E231": [",;:"],
260 "E241": [",;:"],
261 "E242": [",;:"],
262 "E302": [1],
263 "E303": [3],
264 "E501": [85, 79],
265 "E711": ["None", "'if cond is None:'"],
266 "E712": ["True", "'if cond is True:' or 'if cond:'"],
267 "E901": ["SyntaxError", "Invalid Syntax"],
268 }
269
270
271 def getMessage(code, *args):
272 """
273 Function to get a translated and formatted message for a given code.
274
275 @param code message code (string)
276 @param args arguments for a formatted message (list)
277 @return translated and formatted message (string)
278 """
279 if code in pep8_messages:
280 return code + " " + QCoreApplication.translate("pep8",
281 pep8_messages[code]).format(*args)
282 else:
283 return code + " " + QCoreApplication.translate("pep8",
284 "no message for this code defined")
285
286 ##############################################################################
287 # Plugins (check functions) for physical lines
288 ##############################################################################
289
290
291 def tabs_or_spaces(physical_line, indent_char):
292 r"""
293 Never mix tabs and spaces.
294
295 The most popular way of indenting Python is with spaces only. The
296 second-most popular way is with tabs only. Code indented with a mixture
297 of tabs and spaces should be converted to using spaces exclusively. When
298 invoking the Python command line interpreter with the -t option, it issues
299 warnings about code that illegally mixes tabs and spaces. When using -tt
300 these warnings become errors. These options are highly recommended!
301
302 Okay: if a == 0:\n a = 1\n b = 1
303 E101: if a == 0:\n a = 1\n\tb = 1
304 """
305 indent = INDENT_REGEX.match(physical_line).group(1)
306 for offset, char in enumerate(indent):
307 if char != indent_char:
308 return offset, "E101"
309
310
311 def tabs_obsolete(physical_line):
312 r"""
313 For new projects, spaces-only are strongly recommended over tabs. Most
314 editors have features that make this easy to do.
315
316 Okay: if True:\n return
317 W191: if True:\n\treturn
318 """
319 indent = INDENT_REGEX.match(physical_line).group(1)
320 if '\t' in indent:
321 return indent.index('\t'), "W191"
322
323
324 def trailing_whitespace(physical_line):
325 r"""
326 JCR: Trailing whitespace is superfluous.
327 FBM: Except when it occurs as part of a blank line (i.e. the line is
328 nothing but whitespace). According to Python docs[1] a line with only
329 whitespace is considered a blank line, and is to be ignored. However,
330 matching a blank line to its indentation level avoids mistakenly
331 terminating a multi-line statement (e.g. class declaration) when
332 pasting code into the standard Python interpreter.
333
334 [1] http://docs.python.org/reference/lexical_analysis.html#blank-lines
335
336 The warning returned varies on whether the line itself is blank, for easier
337 filtering for those who want to indent their blank lines.
338
339 Okay: spam(1)\n#
340 W291: spam(1) \n#
341 W293: class Foo(object):\n \n bang = 12
342 """
343 physical_line = physical_line.rstrip('\n') # chr(10), newline
344 physical_line = physical_line.rstrip('\r') # chr(13), carriage return
345 physical_line = physical_line.rstrip('\x0c') # chr(12), form feed, ^L
346 stripped = physical_line.rstrip(' \t\v')
347 if physical_line != stripped:
348 if stripped:
349 return len(stripped), "W291"
350 else:
351 return 0, "W293"
352
353
354 def trailing_blank_lines(physical_line, lines, line_number):
355 r"""
356 JCR: Trailing blank lines are superfluous.
357
358 Okay: spam(1)
359 W391: spam(1)\n
360 """
361 if not physical_line.rstrip() and line_number == len(lines):
362 return 0, "W391"
363
364
365 def missing_newline(physical_line):
366 """
367 JCR: The last line should have a newline.
368
369 Reports warning W292.
370 """
371 if physical_line.rstrip() == physical_line:
372 return len(physical_line), "W292"
373
374
375 def maximum_line_length(physical_line, max_line_length):
376 """
377 Limit all lines to a maximum of 79 characters.
378
379 There are still many devices around that are limited to 80 character
380 lines; plus, limiting windows to 80 characters makes it possible to have
381 several windows side-by-side. The default wrapping on such devices looks
382 ugly. Therefore, please limit all lines to a maximum of 79 characters.
383 For flowing long blocks of text (docstrings or comments), limiting the
384 length to 72 characters is recommended.
385
386 Reports error E501.
387 """
388 line = physical_line.rstrip()
389 length = len(line)
390 if length > max_line_length and not noqa(line):
391 if hasattr(line, 'decode'): # Python 2
392 # The line could contain multi-byte characters
393 try:
394 length = len(line.decode('utf-8'))
395 except UnicodeError:
396 pass
397 if length > max_line_length:
398 return max_line_length, "E501", length, max_line_length
399
400
401 ##############################################################################
402 # Plugins (check functions) for logical lines
403 ##############################################################################
404
405
406 def blank_lines(logical_line, blank_lines, indent_level, line_number,
407 previous_logical, previous_indent_level):
408 r"""
409 Separate top-level function and class definitions with two blank lines.
410
411 Method definitions inside a class are separated by a single blank line.
412
413 Extra blank lines may be used (sparingly) to separate groups of related
414 functions. Blank lines may be omitted between a bunch of related
415 one-liners (e.g. a set of dummy implementations).
416
417 Use blank lines in functions, sparingly, to indicate logical sections.
418
419 Okay: def a():\n pass\n\n\ndef b():\n pass
420 Okay: def a():\n pass\n\n\n# Foo\n# Bar\n\ndef b():\n pass
421
422 E301: class Foo:\n b = 0\n def bar():\n pass
423 E302: def a():\n pass\n\ndef b(n):\n pass
424 E303: def a():\n pass\n\n\n\ndef b(n):\n pass
425 E303: def a():\n\n\n\n pass
426 E304: @decorator\n\ndef a():\n pass
427 """
428 if line_number < 3 and not previous_logical:
429 return # Don't expect blank lines before the first line
430 if previous_logical.startswith('@'):
431 if blank_lines:
432 yield 0, "E304"
433 elif blank_lines > 2 or (indent_level and blank_lines == 2):
434 yield 0, "E303", blank_lines
435 elif logical_line.startswith(('def ', 'class ', '@')):
436 if indent_level:
437 if not (blank_lines or previous_indent_level < indent_level or
438 DOCSTRING_REGEX.match(previous_logical)):
439 yield 0, "E301"
440 elif blank_lines != 2:
441 yield 0, "E302", blank_lines
442
443
444 def extraneous_whitespace(logical_line):
445 """
446 Avoid extraneous whitespace in the following situations:
447
448 - Immediately inside parentheses, brackets or braces.
449
450 - Immediately before a comma, semicolon, or colon.
451
452 Okay: spam(ham[1], {eggs: 2})
453 E201: spam( ham[1], {eggs: 2})
454 E201: spam(ham[ 1], {eggs: 2})
455 E201: spam(ham[1], { eggs: 2})
456 E202: spam(ham[1], {eggs: 2} )
457 E202: spam(ham[1 ], {eggs: 2})
458 E202: spam(ham[1], {eggs: 2 })
459
460 E203: if x == 4: print x, y; x, y = y , x
461 E203: if x == 4: print x, y ; x, y = y, x
462 E203: if x == 4 : print x, y; x, y = y, x
463 """
464 line = logical_line
465 for match in EXTRANEOUS_WHITESPACE_REGEX.finditer(line):
466 text = match.group()
467 char = text.strip()
468 found = match.start()
469 if text == char + ' ':
470 # assert char in '([{'
471 yield found + 1, "E201", char
472 elif line[found - 1] != ',':
473 code = ('E202' if char in '}])' else 'E203') # if char in ',;:'
474 yield found, code, char
475
476
477 def whitespace_around_keywords(logical_line):
478 r"""
479 Avoid extraneous whitespace around keywords.
480
481 Okay: True and False
482 E271: True and False
483 E272: True and False
484 E273: True and\tFalse
485 E274: True\tand False
486 """
487 for match in KEYWORD_REGEX.finditer(logical_line):
488 before, after = match.groups()
489
490 if '\t' in before:
491 yield match.start(1), "E274"
492 elif len(before) > 1:
493 yield match.start(1), "E272"
494
495 if '\t' in after:
496 yield match.start(2), "E273"
497 elif len(after) > 1:
498 yield match.start(2), "E271"
499
500
501 def missing_whitespace(logical_line):
502 """
503 JCR: Each comma, semicolon or colon should be followed by whitespace.
504
505 Okay: [a, b]
506 Okay: (3,)
507 Okay: a[1:4]
508 Okay: a[:4]
509 Okay: a[1:]
510 Okay: a[1:4:2]
511 E231: ['a','b']
512 E231: foo(bar,baz)
513 E231: [{'a':'b'}]
514 """
515 line = logical_line
516 for index in range(len(line) - 1):
517 char = line[index]
518 if char in ',;:' and line[index + 1] not in WHITESPACE:
519 before = line[:index]
520 if char == ':' and before.count('[') > before.count(']') and \
521 before.rfind('{') < before.rfind('['):
522 continue # Slice syntax, no space required
523 if char == ',' and line[index + 1] == ')':
524 continue # Allow tuple with only one element: (3,)
525 yield index, "E231", char
526
527
528 def indentation(logical_line, previous_logical, indent_char,
529 indent_level, previous_indent_level):
530 r"""
531 Use 4 spaces per indentation level.
532
533 For really old code that you don't want to mess up, you can continue to
534 use 8-space tabs.
535
536 Okay: a = 1
537 Okay: if a == 0:\n a = 1
538 E111: a = 1
539
540 Okay: for item in items:\n pass
541 E112: for item in items:\npass
542
543 Okay: a = 1\nb = 2
544 E113: a = 1\n b = 2
545 """
546 if indent_char == ' ' and indent_level % 4:
547 yield 0, "E111"
548 indent_expect = previous_logical.endswith(':')
549 if indent_expect and indent_level <= previous_indent_level:
550 yield 0, "E112"
551 if indent_level > previous_indent_level and not indent_expect:
552 yield 0, "E113"
553
554
555 def continued_indentation(logical_line, tokens, indent_level, hang_closing,
556 noqa, verbose):
557 r"""
558 Continuation lines should align wrapped elements either vertically using
559 Python's implicit line joining inside parentheses, brackets and braces, or
560 using a hanging indent.
561
562 When using a hanging indent the following considerations should be applied:
563
564 - there should be no arguments on the first line, and
565
566 - further indentation should be used to clearly distinguish itself as a
567 continuation line.
568
569 Okay: a = (\n)
570 E123: a = (\n )
571
572 Okay: a = (\n 42)
573 E121: a = (\n 42)
574 E122: a = (\n42)
575 E123: a = (\n 42\n )
576 E124: a = (24,\n 42\n)
577 E125: if (a or\n b):\n pass
578 E126: a = (\n 42)
579 E127: a = (24,\n 42)
580 E128: a = (24,\n 42)
581 """
582 first_row = tokens[0][2][0]
583 nrows = 1 + tokens[-1][2][0] - first_row
584 if noqa or nrows == 1:
585 return
586
587 # indent_next tells us whether the next block is indented; assuming
588 # that it is indented by 4 spaces, then we should not allow 4-space
589 # indents on the final continuation line; in turn, some other
590 # indents are allowed to have an extra 4 spaces.
591 indent_next = logical_line.endswith(':')
592
593 row = depth = 0
594 # remember how many brackets were opened on each line
595 parens = [0] * nrows
596 # relative indents of physical lines
597 rel_indent = [0] * nrows
598 # visual indents
599 indent_chances = {}
600 last_indent = tokens[0][2]
601 indent = [last_indent[1]]
602 if verbose >= 3:
603 print(">>> " + tokens[0][4].rstrip())
604
605 for token_type, text, start, end, line in tokens:
606
607 last_token_multiline = (start[0] != end[0])
608 newline = row < start[0] - first_row
609 if newline:
610 row = start[0] - first_row
611 newline = (not last_token_multiline and
612 token_type not in (tokenize.NL, tokenize.NEWLINE))
613
614 if newline:
615 # this is the beginning of a continuation line.
616 last_indent = start
617 if verbose >= 3:
618 print("... " + line.rstrip())
619
620 # record the initial indent.
621 rel_indent[row] = expand_indent(line) - indent_level
622
623 if depth:
624 # a bracket expression in a continuation line.
625 # find the line that it was opened on
626 for open_row in range(row - 1, -1, -1):
627 if parens[open_row]:
628 break
629 else:
630 # an unbracketed continuation line (ie, backslash)
631 open_row = 0
632 hang = rel_indent[row] - rel_indent[open_row]
633 close_bracket = (token_type == tokenize.OP and text in ']})')
634 visual_indent = (not close_bracket and hang > 0 and
635 indent_chances.get(start[1]))
636
637 if close_bracket and indent[depth]:
638 # closing bracket for visual indent
639 if start[1] != indent[depth]:
640 yield start, "E124"
641 elif close_bracket and not hang:
642 # closing bracket matches indentation of opening bracket's line
643 if hang_closing:
644 yield start, "E133"
645 elif visual_indent is True:
646 # visual indent is verified
647 if not indent[depth]:
648 indent[depth] = start[1]
649 elif visual_indent in (text, str):
650 # ignore token lined up with matching one from a previous line
651 pass
652 elif indent[depth] and start[1] < indent[depth]:
653 # visual indent is broken
654 yield start, "E128"
655 elif hang == 4 or (indent_next and rel_indent[row] == 8):
656 # hanging indent is verified
657 if close_bracket and not hang_closing:
658 yield (start, "E123")
659 else:
660 # indent is broken
661 if hang <= 0:
662 error = "E122"
663 elif indent[depth]:
664 error = "E127"
665 elif hang % 4:
666 error = "E121"
667 else:
668 error = "E126"
669 yield start, error
670
671 # look for visual indenting
672 if (parens[row] and token_type not in (tokenize.NL, tokenize.COMMENT)
673 and not indent[depth]):
674 indent[depth] = start[1]
675 indent_chances[start[1]] = True
676 if verbose >= 4:
677 print("bracket depth %s indent to %s" % (depth, start[1]))
678 # deal with implicit string concatenation
679 elif (token_type in (tokenize.STRING, tokenize.COMMENT) or
680 text in ('u', 'ur', 'b', 'br')):
681 indent_chances[start[1]] = str
682 # special case for the "if" statement because len("if (") == 4
683 elif not indent_chances and not row and not depth and text == 'if':
684 indent_chances[end[1] + 1] = True
685
686 # keep track of bracket depth
687 if token_type == tokenize.OP:
688 if text in '([{':
689 depth += 1
690 indent.append(0)
691 parens[row] += 1
692 if verbose >= 4:
693 print("bracket depth %s seen, col %s, visual min = %s" %
694 (depth, start[1], indent[depth]))
695 elif text in ')]}' and depth > 0:
696 # parent indents should not be more than this one
697 prev_indent = indent.pop() or last_indent[1]
698 for d in range(depth):
699 if indent[d] > prev_indent:
700 indent[d] = 0
701 for ind in list(indent_chances):
702 if ind >= prev_indent:
703 del indent_chances[ind]
704 depth -= 1
705 if depth:
706 indent_chances[indent[depth]] = True
707 for idx in range(row, -1, -1):
708 if parens[idx]:
709 parens[idx] -= 1
710 rel_indent[row] = rel_indent[idx]
711 break
712 assert len(indent) == depth + 1
713 if start[1] not in indent_chances:
714 # allow to line up tokens
715 indent_chances[start[1]] = text
716
717 if indent_next and expand_indent(line) == indent_level + 4:
718 yield last_indent, "E125"
719
720
721 def whitespace_before_parameters(logical_line, tokens):
722 """
723 Avoid extraneous whitespace in the following situations:
724
725 - Immediately before the open parenthesis that starts the argument
726 list of a function call.
727
728 - Immediately before the open parenthesis that starts an indexing or
729 slicing.
730
731 Okay: spam(1)
732 E211: spam (1)
733
734 Okay: dict['key'] = list[index]
735 E211: dict ['key'] = list[index]
736 E211: dict['key'] = list [index]
737 """
738 prev_type, prev_text, __, prev_end, __ = tokens[0]
739 for index in range(1, len(tokens)):
740 token_type, text, start, end, __ = tokens[index]
741 if (token_type == tokenize.OP and
742 text in '([' and
743 start != prev_end and
744 (prev_type == tokenize.NAME or prev_text in '}])') and
745 # Syntax "class A (B):" is allowed, but avoid it
746 (index < 2 or tokens[index - 2][1] != 'class') and
747 # Allow "return (a.foo for a in range(5))"
748 not keyword.iskeyword(prev_text)):
749 yield prev_end, "E211", text
750 prev_type = token_type
751 prev_text = text
752 prev_end = end
753
754
755 def whitespace_around_operator(logical_line):
756 """
757 Avoid extraneous whitespace in the following situations:
758
759 - More than one space around an assignment (or other) operator to
760 align it with another.
761
762 Okay: a = 12 + 3
763 E221: a = 4 + 5
764 E222: a = 4 + 5
765 E223: a = 4\t+ 5
766 E224: a = 4 +\t5
767 """
768 for match in OPERATOR_REGEX.finditer(logical_line):
769 before, after = match.groups()
770
771 if '\t' in before:
772 yield match.start(1), "E223"
773 elif len(before) > 1:
774 yield match.start(1), "E221"
775
776 if '\t' in after:
777 yield match.start(2), "E224"
778 elif len(after) > 1:
779 yield match.start(2), "E222"
780
781 def missing_whitespace_around_operator(logical_line, tokens):
782 r"""
783 - Always surround these binary operators with a single space on
784 either side: assignment (=), augmented assignment (+=, -= etc.),
785 comparisons (==, <, >, !=, <>, <=, >=, in, not in, is, is not),
786 Booleans (and, or, not).
787
788 - Use spaces around arithmetic operators.
789
790 Okay: i = i + 1
791 Okay: submitted += 1
792 Okay: x = x * 2 - 1
793 Okay: hypot2 = x * x + y * y
794 Okay: c = (a + b) * (a - b)
795 Okay: foo(bar, key='word', *args, **kwargs)
796 Okay: alpha[:-i]
797
798 E225: i=i+1
799 E225: submitted +=1
800 E225: x = x /2 - 1
801 E225: z = x **y
802 E226: c = (a+b) * (a-b)
803 E226: hypot2 = x*x + y*y
804 E227: c = a|b
805 E228: msg = fmt%(errno, errmsg)
806 """
807 parens = 0
808 need_space = False
809 prev_type = tokenize.OP
810 prev_text = prev_end = None
811 for token_type, text, start, end, line in tokens:
812 if token_type in (tokenize.NL, tokenize.NEWLINE, tokenize.ERRORTOKEN):
813 # ERRORTOKEN is triggered by backticks in Python 3
814 continue
815 if text in ('(', 'lambda'):
816 parens += 1
817 elif text == ')':
818 parens -= 1
819 if need_space:
820 if start != prev_end:
821 # Found a (probably) needed space
822 if need_space is not True and not need_space[1]:
823 yield need_space[0], "E225"
824 need_space = False
825 elif text == '>' and prev_text in ('<', '-'):
826 # Tolerate the "<>" operator, even if running Python 3
827 # Deal with Python 3's annotated return value "->"
828 pass
829 else:
830 if need_space is True or need_space[1]:
831 # A needed trailing space was not found
832 yield prev_end, "E225"
833 else:
834 code = 'E226'
835 if prev_text == '%':
836 code = 'E228'
837 elif prev_text not in ARITHMETIC_OP:
838 code = 'E227'
839 yield need_space[0], code
840 need_space = False
841 elif token_type == tokenize.OP and prev_end is not None:
842 if text == '=' and parens:
843 # Allow keyword args or defaults: foo(bar=None).
844 pass
845 elif text in WS_NEEDED_OPERATORS:
846 need_space = True
847 elif text in UNARY_OPERATORS:
848 # Check if the operator is being used as a binary operator
849 # Allow unary operators: -123, -x, +1.
850 # Allow argument unpacking: foo(*args, **kwargs).
851 if prev_type == tokenize.OP:
852 binary_usage = (prev_text in '}])')
853 elif prev_type == tokenize.NAME:
854 binary_usage = (prev_text not in KEYWORDS)
855 else:
856 binary_usage = (prev_type not in SKIP_TOKENS)
857
858 if binary_usage:
859 need_space = None
860 elif text in WS_OPTIONAL_OPERATORS:
861 need_space = None
862
863 if need_space is None:
864 # Surrounding space is optional, but ensure that
865 # trailing space matches opening space
866 need_space = (prev_end, start != prev_end)
867 elif need_space and start == prev_end:
868 # A needed opening space was not found
869 yield prev_end, "E225"
870 need_space = False
871 prev_type = token_type
872 prev_text = text
873 prev_end = end
874
875
876 def whitespace_around_comma(logical_line):
877 """
878 Avoid extraneous whitespace in the following situations:
879
880 - More than one space around an assignment (or other) operator to
881 align it with another.
882
883 JCR: This should also be applied around comma etc.
884 Note: these checks are disabled by default
885
886 Okay: a = (1, 2)
887 E241: a = (1, 2)
888 E242: a = (1,\t2)
889 """
890 line = logical_line
891 for m in WHITESPACE_AFTER_COMMA_REGEX.finditer(line):
892 found = m.start() + 1
893 if '\t' in m.group():
894 yield found, "E242", m.group()[0]
895 else:
896 yield found, "E241", m.group()[0]
897
898
899 def whitespace_around_named_parameter_equals(logical_line, tokens):
900 """
901 Don't use spaces around the '=' sign when used to indicate a
902 keyword argument or a default parameter value.
903
904 Okay: def complex(real, imag=0.0):
905 Okay: return magic(r=real, i=imag)
906 Okay: boolean(a == b)
907 Okay: boolean(a != b)
908 Okay: boolean(a <= b)
909 Okay: boolean(a >= b)
910
911 E251: def complex(real, imag = 0.0):
912 E251: return magic(r = real, i = imag)
913 """
914 parens = 0
915 no_space = False
916 prev_end = None
917 message = "E251"
918 for token_type, text, start, end, line in tokens:
919 if no_space:
920 no_space = False
921 if start != prev_end:
922 yield prev_end, message
923 elif token_type == tokenize.OP:
924 if text == '(':
925 parens += 1
926 elif text == ')':
927 parens -= 1
928 elif parens and text == '=':
929 no_space = True
930 if start != prev_end:
931 yield prev_end, message
932 prev_end = end
933
934
935 def whitespace_before_inline_comment(logical_line, tokens):
936 """
937 Separate inline comments by at least two spaces.
938
939 An inline comment is a comment on the same line as a statement. Inline
940 comments should be separated by at least two spaces from the statement.
941 They should start with a # and a single space.
942
943 Okay: x = x + 1 # Increment x
944 Okay: x = x + 1 # Increment x
945 E261: x = x + 1 # Increment x
946 E262: x = x + 1 #Increment x
947 E262: x = x + 1 # Increment x
948 """
949 prev_end = (0, 0)
950 for token_type, text, start, end, line in tokens:
951 if token_type == tokenize.COMMENT:
952 if not line[:start[1]].strip():
953 continue
954 if prev_end[0] == start[0] and start[1] < prev_end[1] + 2:
955 yield prev_end, "E261"
956 symbol, sp, comment = text.partition(' ')
957 if symbol not in ('#', '#:') or comment[:1].isspace():
958 yield start, "E262"
959 elif token_type != tokenize.NL:
960 prev_end = end
961
962
963 def imports_on_separate_lines(logical_line):
964 r"""
965 Imports should usually be on separate lines.
966
967 Okay: import os\nimport sys
968 E401: import sys, os
969
970 Okay: from subprocess import Popen, PIPE
971 Okay: from myclas import MyClass
972 Okay: from foo.bar.yourclass import YourClass
973 Okay: import myclass
974 Okay: import foo.bar.yourclass
975 """
976 line = logical_line
977 if line.startswith('import '):
978 found = line.find(',')
979 if -1 < found and ';' not in line[:found]:
980 yield found, "E401"
981
982
983 def compound_statements(logical_line):
984 r"""
985 Compound statements (multiple statements on the same line) are
986 generally discouraged.
987
988 While sometimes it's okay to put an if/for/while with a small body
989 on the same line, never do this for multi-clause statements. Also
990 avoid folding such long lines!
991
992 Okay: if foo == 'blah':\n do_blah_thing()
993 Okay: do_one()
994 Okay: do_two()
995 Okay: do_three()
996
997 E701: if foo == 'blah': do_blah_thing()
998 E701: for x in lst: total += x
999 E701: while t < 10: t = delay()
1000 E701: if foo == 'blah': do_blah_thing()
1001 E701: else: do_non_blah_thing()
1002 E701: try: something()
1003 E701: finally: cleanup()
1004 E701: if foo == 'blah': one(); two(); three()
1005
1006 E702: do_one(); do_two(); do_three()
1007 E703: do_four(); # useless semicolon
1008 """
1009 line = logical_line
1010 last_char = len(line) - 1
1011 found = line.find(':')
1012 while -1 < found < last_char:
1013 before = line[:found]
1014 if (before.count('{') <= before.count('}') and # {'a': 1} (dict)
1015 before.count('[') <= before.count(']') and # [1:2] (slice)
1016 before.count('(') <= before.count(')') and # (Python 3 annotation)
1017 not LAMBDA_REGEX.search(before)): # lambda x: x
1018 yield found, "E701"
1019 found = line.find(':', found + 1)
1020 found = line.find(';')
1021 while -1 < found:
1022 if found < last_char:
1023 yield found, "E702"
1024 else:
1025 yield found, "E703"
1026 found = line.find(';', found + 1)
1027
1028
1029 def explicit_line_join(logical_line, tokens):
1030 r"""
1031 Avoid explicit line join between brackets.
1032
1033 The preferred way of wrapping long lines is by using Python's implied line
1034 continuation inside parentheses, brackets and braces. Long lines can be
1035 broken over multiple lines by wrapping expressions in parentheses. These
1036 should be used in preference to using a backslash for line continuation.
1037
1038 E502: aaa = [123, \\n 123]
1039 E502: aaa = ("bbb " \\n "ccc")
1040
1041 Okay: aaa = [123,\n 123]
1042 Okay: aaa = ("bbb "\n "ccc")
1043 Okay: aaa = "bbb " \\n "ccc"
1044 """
1045 prev_start = prev_end = parens = 0
1046 backslash = None
1047 for token_type, text, start, end, line in tokens:
1048 if start[0] != prev_start and parens and backslash:
1049 yield backslash, "E502"
1050 if end[0] != prev_end:
1051 if line.rstrip('\r\n').endswith('\\'):
1052 backslash = (end[0], len(line.splitlines()[-1]) - 1)
1053 else:
1054 backslash = None
1055 prev_start = prev_end = end[0]
1056 else:
1057 prev_start = start[0]
1058 if token_type == tokenize.OP:
1059 if text in '([{':
1060 parens += 1
1061 elif text in ')]}':
1062 parens -= 1
1063
1064
1065 def comparison_to_singleton(logical_line, noqa):
1066 """
1067 Comparisons to singletons like None should always be done
1068 with "is" or "is not", never the equality operators.
1069
1070 Okay: if arg is not None:
1071 E711: if arg != None:
1072 E712: if arg == True:
1073
1074 Also, beware of writing if x when you really mean if x is not None --
1075 e.g. when testing whether a variable or argument that defaults to None was
1076 set to some other value. The other value might have a type (such as a
1077 container) that could be false in a boolean context!
1078 """
1079 match = not noqa and COMPARE_SINGLETON_REGEX.search(logical_line)
1080 if match:
1081 same = (match.group(1) == '==')
1082 singleton = match.group(2)
1083 msg = "'if cond is %s:'" % (('' if same else 'not ') + singleton)
1084 if singleton in ('None',):
1085 code = 'E711'
1086 else:
1087 code = 'E712'
1088 nonzero = ((singleton == 'True' and same) or
1089 (singleton == 'False' and not same))
1090 msg += " or 'if %scond:'" % ('' if nonzero else 'not ')
1091 yield match.start(1), code, singleton, msg
1092
1093
1094 def comparison_type(logical_line):
1095 """
1096 Object type comparisons should always use isinstance() instead of
1097 comparing types directly.
1098
1099 Okay: if isinstance(obj, int):
1100 E721: if type(obj) is type(1):
1101
1102 When checking if an object is a string, keep in mind that it might be a
1103 unicode string too! In Python 2.3, str and unicode have a common base
1104 class, basestring, so you can do:
1105
1106 Okay: if isinstance(obj, basestring):
1107 Okay: if type(a1) is type(b1):
1108 """
1109 match = COMPARE_TYPE_REGEX.search(logical_line)
1110 if match:
1111 inst = match.group(1)
1112 if inst and isidentifier(inst) and inst not in SINGLETONS:
1113 return # Allow comparison for types which are not obvious
1114 yield match.start(), "E721"
1115
1116
1117 def python_3000_has_key(logical_line):
1118 r"""
1119 The {}.has_key() method is removed in the Python 3.
1120 Use the 'in' operation instead.
1121
1122 Okay: if "alph" in d:\n print d["alph"]
1123 W601: assert d.has_key('alph')
1124 """
1125 pos = logical_line.find('.has_key(')
1126 if pos > -1:
1127 yield pos, "W601"
1128
1129
1130 def python_3000_raise_comma(logical_line):
1131 """
1132 When raising an exception, use "raise ValueError('message')"
1133 instead of the older form "raise ValueError, 'message'".
1134
1135 The paren-using form is preferred because when the exception arguments
1136 are long or include string formatting, you don't need to use line
1137 continuation characters thanks to the containing parentheses. The older
1138 form is removed in Python 3.
1139
1140 Okay: raise DummyError("Message")
1141 W602: raise DummyError, "Message"
1142 """
1143 match = RAISE_COMMA_REGEX.match(logical_line)
1144 if match and not RERAISE_COMMA_REGEX.match(logical_line):
1145 yield match.end() - 1, "W602"
1146
1147
1148 def python_3000_not_equal(logical_line):
1149 """
1150 != can also be written <>, but this is an obsolete usage kept for
1151 backwards compatibility only. New code should always use !=.
1152 The older syntax is removed in Python 3.
1153
1154 Okay: if a != 'no':
1155 W603: if a <> 'no':
1156 """
1157 pos = logical_line.find('<>')
1158 if pos > -1:
1159 yield pos, "W603"
1160
1161
1162 def python_3000_backticks(logical_line):
1163 """
1164 Backticks are removed in Python 3.
1165 Use repr() instead.
1166
1167 Okay: val = repr(1 + 2)
1168 W604: val = `1 + 2`
1169 """
1170 pos = logical_line.find('`')
1171 if pos > -1:
1172 yield pos, "W604"
1173
1174
1175 ##############################################################################
1176 # Helper functions
1177 ##############################################################################
1178
1179
1180 if '' == ''.encode():
1181 # Python 2: implicit encoding.
1182 def readlines(filename):
1183 f = open(filename)
1184 try:
1185 return f.readlines()
1186 finally:
1187 f.close()
1188 isidentifier = re.compile(r'[a-zA-Z_]\w*').match
1189 stdin_get_value = sys.stdin.read
1190 else:
1191 # Python 3
1192 def readlines(filename): # __IGNORE_WARNING__
1193 f = open(filename, 'rb')
1194 try:
1195 coding, lines = tokenize.detect_encoding(f.readline)
1196 f = TextIOWrapper(f, coding, line_buffering=True)
1197 return [l.decode(coding) for l in lines] + f.readlines()
1198 except (LookupError, SyntaxError, UnicodeError):
1199 f.close()
1200 # Fall back if files are improperly declared
1201 f = open(filename, encoding='latin-1')
1202 return f.readlines()
1203 finally:
1204 f.close()
1205 isidentifier = str.isidentifier
1206
1207 def stdin_get_value():
1208 return TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
1209 readlines.__doc__ = " Read the source code."
1210 noqa = re.compile(r'# no(?:qa|pep8)\b', re.I).search
1211
1212
1213 def expand_indent(line):
1214 r"""
1215 Return the amount of indentation.
1216 Tabs are expanded to the next multiple of 8.
1217
1218 >>> expand_indent(' ')
1219 4
1220 >>> expand_indent('\t')
1221 8
1222 >>> expand_indent(' \t')
1223 8
1224 >>> expand_indent(' \t')
1225 8
1226 >>> expand_indent(' \t')
1227 16
1228 """
1229 if '\t' not in line:
1230 return len(line) - len(line.lstrip())
1231 result = 0
1232 for char in line:
1233 if char == '\t':
1234 result = result // 8 * 8 + 8
1235 elif char == ' ':
1236 result += 1
1237 else:
1238 break
1239 return result
1240
1241
1242 def mute_string(text):
1243 """
1244 Replace contents with 'xxx' to prevent syntax matching.
1245
1246 >>> mute_string('"abc"')
1247 '"xxx"'
1248 >>> mute_string("'''abc'''")
1249 "'''xxx'''"
1250 >>> mute_string("r'abc'")
1251 "r'xxx'"
1252 """
1253 # String modifiers (e.g. u or r)
1254 start = text.index(text[-1]) + 1
1255 end = len(text) - 1
1256 # Triple quotes
1257 if text[-3:] in ('"""', "'''"):
1258 start += 2
1259 end -= 2
1260 return text[:start] + 'x' * (end - start) + text[end:]
1261
1262
1263 def parse_udiff(diff, patterns=None, parent='.'):
1264 """Return a dictionary of matching lines."""
1265 # For each file of the diff, the entry key is the filename,
1266 # and the value is a set of row numbers to consider.
1267 rv = {}
1268 path = nrows = None
1269 for line in diff.splitlines():
1270 if nrows:
1271 if line[:1] != '-':
1272 nrows -= 1
1273 continue
1274 if line[:3] == '@@ ':
1275 hunk_match = HUNK_REGEX.match(line)
1276 row, nrows = [int(g or '1') for g in hunk_match.groups()]
1277 rv[path].update(range(row, row + nrows))
1278 elif line[:3] == '+++':
1279 path = line[4:].split('\t', 1)[0]
1280 if path[:2] == 'b/':
1281 path = path[2:]
1282 rv[path] = set()
1283 return dict([(os.path.join(parent, path), rows)
1284 for (path, rows) in rv.items()
1285 if rows and filename_match(path, patterns)])
1286
1287
1288 def filename_match(filename, patterns, default=True):
1289 """
1290 Check if patterns contains a pattern that matches filename.
1291 If patterns is unspecified, this always returns True.
1292 """
1293 if not patterns:
1294 return default
1295 return any(fnmatch(filename, pattern) for pattern in patterns)
1296
1297
1298 ##############################################################################
1299 # Framework to run all checks
1300 ##############################################################################
1301
1302
1303 _checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
1304
1305
1306 def register_check(check, codes=None):
1307 """
1308 Register a new check object.
1309 """
1310 def _add_check(check, kind, codes, args):
1311 if check in _checks[kind]:
1312 _checks[kind][check][0].extend(codes or [])
1313 else:
1314 _checks[kind][check] = (codes or [''], args)
1315 if inspect.isfunction(check):
1316 args = inspect.getargspec(check)[0]
1317 if args and args[0] in ('physical_line', 'logical_line'):
1318 if codes is None:
1319 codes = ERRORCODE_REGEX.findall(check.__doc__ or '')
1320 _add_check(check, args[0], codes, args)
1321 elif inspect.isclass(check):
1322 if inspect.getargspec(check.__init__)[0][:2] == ['self', 'tree']:
1323 _add_check(check, 'tree', codes, None)
1324
1325
1326 def init_checks_registry():
1327 """
1328 Register all globally visible functions where the first argument name
1329 is 'physical_line' or 'logical_line'.
1330 """
1331 mod = inspect.getmodule(register_check)
1332 for (name, function) in inspect.getmembers(mod, inspect.isfunction):
1333 register_check(function)
1334 init_checks_registry()
1335
1336
1337 class Checker(object):
1338 """
1339 Load a Python source file, tokenize it, check coding style.
1340 """
1341
1342 def __init__(self, filename=None, lines=None,
1343 options=None, report=None, **kwargs):
1344 if options is None:
1345 options = StyleGuide(kwargs).options
1346 else:
1347 assert not kwargs
1348 self._io_error = None
1349 self._physical_checks = options.physical_checks
1350 self._logical_checks = options.logical_checks
1351 self._ast_checks = options.ast_checks
1352 self.max_line_length = options.max_line_length
1353 self.hang_closing = options.hang_closing
1354 self.verbose = options.verbose
1355 self.filename = filename
1356 if filename is None:
1357 self.filename = 'stdin'
1358 self.lines = lines or []
1359 elif filename == '-':
1360 self.filename = 'stdin'
1361 self.lines = stdin_get_value().splitlines(True)
1362 elif lines is None:
1363 try:
1364 self.lines = readlines(filename)
1365 except IOError:
1366 exc_type, exc = sys.exc_info()[:2]
1367 self._io_error = '%s: %s' % (exc_type.__name__, exc)
1368 self.lines = []
1369 else:
1370 self.lines = lines
1371 if self.lines:
1372 ord0 = ord(self.lines[0][0])
1373 if ord0 in (0xef, 0xfeff): # Strip the UTF-8 BOM
1374 if ord0 == 0xfeff:
1375 self.lines[0] = self.lines[0][1:]
1376 elif self.lines[0][:3] == '\xef\xbb\xbf':
1377 self.lines[0] = self.lines[0][3:]
1378 self.report = report or options.report
1379 self.report_error = self.report.error
1380 self.report_error_args = self.report.error_args
1381
1382 # added for eric5 integration
1383 self.options = options
1384
1385 def report_invalid_syntax(self):
1386 exc_type, exc = sys.exc_info()[:2]
1387 if len(exc.args) > 1:
1388 offset = exc.args[1]
1389 if len(offset) > 2:
1390 offset = offset[1:3]
1391 else:
1392 offset = (1, 0)
1393 self.report_error_args(offset[0], offset[1] or 0,
1394 'E901', self.report_invalid_syntax,
1395 exc_type.__name__, exc.args[0])
1396 report_invalid_syntax.__doc__ = " Check if the syntax is valid."
1397
1398 def readline(self):
1399 """
1400 Get the next line from the input buffer.
1401 """
1402 self.line_number += 1
1403 if self.line_number > len(self.lines):
1404 return ''
1405 return self.lines[self.line_number - 1]
1406
1407 def readline_check_physical(self):
1408 """
1409 Check and return the next physical line. This method can be
1410 used to feed tokenize.generate_tokens.
1411 """
1412 line = self.readline()
1413 if line:
1414 self.check_physical(line)
1415 return line
1416
1417 def run_check(self, check, argument_names):
1418 """
1419 Run a check plugin.
1420 """
1421 arguments = []
1422 for name in argument_names:
1423 arguments.append(getattr(self, name))
1424 return check(*arguments)
1425
1426 def check_physical(self, line):
1427 """
1428 Run all physical checks on a raw input line.
1429 """
1430 self.physical_line = line
1431 if self.indent_char is None and line[:1] in WHITESPACE:
1432 self.indent_char = line[0]
1433 for name, check, argument_names in self._physical_checks:
1434 result = self.run_check(check, argument_names)
1435 if result is not None:
1436 offset, code, *args = result
1437 self.report_error_args(self.line_number, offset, code, check,
1438 *args)
1439
1440 def build_tokens_line(self):
1441 """
1442 Build a logical line from tokens.
1443 """
1444 self.mapping = []
1445 logical = []
1446 comments = []
1447 length = 0
1448 previous = None
1449 for token in self.tokens:
1450 token_type, text = token[0:2]
1451 if token_type == tokenize.COMMENT:
1452 comments.append(text)
1453 continue
1454 if token_type in SKIP_TOKENS:
1455 continue
1456 if token_type == tokenize.STRING:
1457 text = mute_string(text)
1458 if previous:
1459 end_row, end = previous[3]
1460 start_row, start = token[2]
1461 if end_row != start_row: # different row
1462 prev_text = self.lines[end_row - 1][end - 1]
1463 if prev_text == ',' or (prev_text not in '{[('
1464 and text not in '}])'):
1465 logical.append(' ')
1466 length += 1
1467 elif end != start: # different column
1468 fill = self.lines[end_row - 1][end:start]
1469 logical.append(fill)
1470 length += len(fill)
1471 self.mapping.append((length, token))
1472 logical.append(text)
1473 length += len(text)
1474 previous = token
1475 self.logical_line = ''.join(logical)
1476 self.noqa = comments and noqa(''.join(comments))
1477 # With Python 2, if the line ends with '\r\r\n' the assertion fails
1478 # assert self.logical_line.strip() == self.logical_line
1479
1480 def check_logical(self):
1481 """
1482 Build a line from tokens and run all logical checks on it.
1483 """
1484 self.build_tokens_line()
1485 self.report.increment_logical_line()
1486 first_line = self.lines[self.mapping[0][1][2][0] - 1]
1487 indent = first_line[:self.mapping[0][1][2][1]]
1488 self.previous_indent_level = self.indent_level
1489 self.indent_level = expand_indent(indent)
1490 if self.verbose >= 2:
1491 print(self.logical_line[:80].rstrip())
1492 for name, check, argument_names in self._logical_checks:
1493 if self.verbose >= 4:
1494 print(' ' + name)
1495 for result in self.run_check(check, argument_names):
1496 offset, code, *args = result
1497 if isinstance(offset, tuple):
1498 orig_number, orig_offset = offset
1499 else:
1500 for token_offset, token in self.mapping:
1501 if offset >= token_offset:
1502 orig_number = token[2][0]
1503 orig_offset = (token[2][1] + offset - token_offset)
1504 self.report_error_args(orig_number, orig_offset, code, check,
1505 *args)
1506 self.previous_logical = self.logical_line
1507
1508 def check_ast(self):
1509 try:
1510 tree = compile(''.join(self.lines), '', 'exec', PyCF_ONLY_AST)
1511 except (SyntaxError, TypeError):
1512 return self.report_invalid_syntax()
1513 for name, cls, _ in self._ast_checks:
1514 # extended API for eric5 integration
1515 checker = cls(tree, self.filename, self.options)
1516 for lineno, offset, code, check, *args in checker.run():
1517 if not noqa(self.lines[lineno - 1]):
1518 self.report_error_args(lineno, offset, code, check, *args)
1519
1520 def generate_tokens(self):
1521 if self._io_error:
1522 self.report_error(1, 0, 'E902 %s' % self._io_error, readlines)
1523 tokengen = tokenize.generate_tokens(self.readline_check_physical)
1524 try:
1525 for token in tokengen:
1526 yield token
1527 except (SyntaxError, tokenize.TokenError):
1528 self.report_invalid_syntax()
1529
1530 def check_all(self, expected=None, line_offset=0):
1531 """
1532 Run all checks on the input file.
1533 """
1534 self.report.init_file(self.filename, self.lines, expected, line_offset)
1535 if self._ast_checks:
1536 self.check_ast()
1537 self.line_number = 0
1538 self.indent_char = None
1539 self.indent_level = 0
1540 self.previous_logical = ''
1541 self.tokens = []
1542 self.blank_lines = blank_lines_before_comment = 0
1543 parens = 0
1544 for token in self.generate_tokens():
1545 self.tokens.append(token)
1546 token_type, text = token[0:2]
1547 if self.verbose >= 3:
1548 if token[2][0] == token[3][0]:
1549 pos = '[%s:%s]' % (token[2][1] or '', token[3][1])
1550 else:
1551 pos = 'l.%s' % token[3][0]
1552 print('l.%s\t%s\t%s\t%r' %
1553 (token[2][0], pos, tokenize.tok_name[token[0]], text))
1554 if token_type == tokenize.OP:
1555 if text in '([{':
1556 parens += 1
1557 elif text in '}])':
1558 parens -= 1
1559 elif not parens:
1560 if token_type == tokenize.NEWLINE:
1561 if self.blank_lines < blank_lines_before_comment:
1562 self.blank_lines = blank_lines_before_comment
1563 self.check_logical()
1564 self.tokens = []
1565 self.blank_lines = blank_lines_before_comment = 0
1566 elif token_type == tokenize.NL:
1567 if len(self.tokens) == 1:
1568 # The physical line contains only this token.
1569 self.blank_lines += 1
1570 self.tokens = []
1571 elif token_type == tokenize.COMMENT and len(self.tokens) == 1:
1572 if blank_lines_before_comment < self.blank_lines:
1573 blank_lines_before_comment = self.blank_lines
1574 self.blank_lines = 0
1575 if COMMENT_WITH_NL:
1576 # The comment also ends a physical line
1577 self.tokens = []
1578 return self.report.get_file_results()
1579
1580
1581 class BaseReport(object):
1582 """Collect the results of the checks."""
1583 print_filename = False
1584
1585 def __init__(self, options):
1586 self._benchmark_keys = options.benchmark_keys
1587 self._ignore_code = options.ignore_code
1588 # Results
1589 self.elapsed = 0
1590 self.total_errors = 0
1591 self.counters = dict.fromkeys(self._benchmark_keys, 0)
1592 self.messages = {}
1593
1594 def start(self):
1595 """Start the timer."""
1596 self._start_time = time.time()
1597
1598 def stop(self):
1599 """Stop the timer."""
1600 self.elapsed = time.time() - self._start_time
1601
1602 def init_file(self, filename, lines, expected, line_offset):
1603 """Signal a new file."""
1604 self.filename = filename
1605 self.lines = lines
1606 self.expected = expected or ()
1607 self.line_offset = line_offset
1608 self.file_errors = 0
1609 self.counters['files'] += 1
1610 self.counters['physical lines'] += len(lines)
1611
1612 def increment_logical_line(self):
1613 """Signal a new logical line."""
1614 self.counters['logical lines'] += 1
1615
1616 def error(self, line_number, offset, text, check):
1617 """Report an error, according to options."""
1618 code = text[:4]
1619 if self._ignore_code(code):
1620 return
1621 if code in self.counters:
1622 self.counters[code] += 1
1623 else:
1624 self.counters[code] = 1
1625 self.messages[code] = text[5:]
1626 # Don't care about expected errors or warnings
1627 if code in self.expected:
1628 return
1629 if self.print_filename and not self.file_errors:
1630 print(self.filename)
1631 self.file_errors += 1
1632 self.total_errors += 1
1633 return code
1634
1635 def error_args(self, line_number, offset, code, check, *args):
1636 """Report an error, according to options."""
1637 if self._ignore_code(code):
1638 return
1639 text = getMessage(code, *args)
1640 if code in self.counters:
1641 self.counters[code] += 1
1642 else:
1643 self.counters[code] = 1
1644 self.messages[code] = text[5:]
1645 # Don't care about expected errors or warnings
1646 if code in self.expected:
1647 return
1648 if self.print_filename and not self.file_errors:
1649 print(self.filename)
1650 self.file_errors += 1
1651 self.total_errors += 1
1652 return code
1653
1654 def get_file_results(self):
1655 """Return the count of errors and warnings for this file."""
1656 return self.file_errors
1657
1658 def get_count(self, prefix=''):
1659 """Return the total count of errors and warnings."""
1660 return sum([self.counters[key]
1661 for key in self.messages if key.startswith(prefix)])
1662
1663 def get_statistics(self, prefix=''):
1664 """
1665 Get statistics for message codes that start with the prefix.
1666
1667 prefix='' matches all errors and warnings
1668 prefix='E' matches all errors
1669 prefix='W' matches all warnings
1670 prefix='E4' matches all errors that have to do with imports
1671 """
1672 return ['%-7s %s %s' % (self.counters[key], key, self.messages[key])
1673 for key in sorted(self.messages) if key.startswith(prefix)]
1674
1675 def print_statistics(self, prefix=''):
1676 """Print overall statistics (number of errors and warnings)."""
1677 for line in self.get_statistics(prefix):
1678 print(line)
1679
1680 def print_benchmark(self):
1681 """Print benchmark numbers."""
1682 print('%-7.2f %s' % (self.elapsed, 'seconds elapsed'))
1683 if self.elapsed:
1684 for key in self._benchmark_keys:
1685 print('%-7d %s per second (%d total)' %
1686 (self.counters[key] / self.elapsed, key,
1687 self.counters[key]))
1688
1689
1690 class FileReport(BaseReport):
1691 """Collect the results of the checks and print only the filenames."""
1692 print_filename = True
1693
1694
1695 class StandardReport(BaseReport):
1696 """Collect and print the results of the checks."""
1697
1698 def __init__(self, options):
1699 super(StandardReport, self).__init__(options)
1700 self._fmt = REPORT_FORMAT.get(options.format.lower(),
1701 options.format)
1702 self._repeat = options.repeat
1703 self._show_source = options.show_source
1704 self._show_pep8 = options.show_pep8
1705
1706 def init_file(self, filename, lines, expected, line_offset):
1707 """Signal a new file."""
1708 self._deferred_print = []
1709 return super(StandardReport, self).init_file(
1710 filename, lines, expected, line_offset)
1711
1712 def error(self, line_number, offset, text, check):
1713 """Report an error, according to options."""
1714 code = super(StandardReport, self).error(line_number, offset,
1715 text, check)
1716 if code and (self.counters[code] == 1 or self._repeat):
1717 self._deferred_print.append(
1718 (line_number, offset, code, text[5:], check.__doc__))
1719 return code
1720
1721 def error_args(self, line_number, offset, code, check, *args):
1722 """Report an error, according to options."""
1723 code = super(StandardReport, self).error_args(line_number, offset,
1724 code, check, *args)
1725 if code and (self.counters[code] == 1 or self._repeat):
1726 text = getMessage(code, *args)
1727 self._deferred_print.append(
1728 (line_number, offset, code, text[5:], check.__doc__))
1729 return code
1730
1731 def get_file_results(self):
1732 """Print the result and return the overall count for this file."""
1733 self._deferred_print.sort()
1734 for line_number, offset, code, text, doc in self._deferred_print:
1735 print(self._fmt % {
1736 'path': self.filename,
1737 'row': self.line_offset + line_number, 'col': offset + 1,
1738 'code': code, 'text': text,
1739 })
1740 if self._show_source:
1741 if line_number > len(self.lines):
1742 line = ''
1743 else:
1744 line = self.lines[line_number - 1]
1745 print(line.rstrip())
1746 print(' ' * offset + '^')
1747 if self._show_pep8 and doc:
1748 print(doc.lstrip('\n').rstrip())
1749 return self.file_errors
1750
1751
1752 class DiffReport(StandardReport):
1753 """Collect and print the results for the changed lines only."""
1754
1755 def __init__(self, options):
1756 super(DiffReport, self).__init__(options)
1757 self._selected = options.selected_lines
1758
1759 def error(self, line_number, offset, text, check):
1760 if line_number not in self._selected[self.filename]:
1761 return
1762 return super(DiffReport, self).error(line_number, offset, text, check)
1763
1764
1765 class StyleGuide(object):
1766 """Initialize a PEP-8 instance with few options."""
1767
1768 def __init__(self, *args, **kwargs):
1769 # build options from the command line
1770 self.checker_class = kwargs.pop('checker_class', Checker)
1771 parse_argv = kwargs.pop('parse_argv', False)
1772 config_file = kwargs.pop('config_file', None)
1773 parser = kwargs.pop('parser', None)
1774 options, self.paths = process_options(
1775 parse_argv=parse_argv, config_file=config_file, parser=parser)
1776 if args or kwargs:
1777 # build options from dict
1778 options_dict = dict(*args, **kwargs)
1779 options.__dict__.update(options_dict)
1780 if 'paths' in options_dict:
1781 self.paths = options_dict['paths']
1782
1783 self.runner = self.input_file
1784 self.options = options
1785
1786 if not options.reporter:
1787 options.reporter = BaseReport if options.quiet else StandardReport
1788
1789 for index, value in enumerate(options.exclude):
1790 options.exclude[index] = value.rstrip('/')
1791 options.select = tuple(options.select or ())
1792 if not (options.select or options.ignore or
1793 options.testsuite or options.doctest) and DEFAULT_IGNORE:
1794 # The default choice: ignore controversial checks
1795 options.ignore = tuple(DEFAULT_IGNORE.split(','))
1796 else:
1797 # Ignore all checks which are not explicitly selected
1798 options.ignore = ('',) if options.select else tuple(options.ignore)
1799 options.benchmark_keys = BENCHMARK_KEYS[:]
1800 options.ignore_code = self.ignore_code
1801 options.physical_checks = self.get_checks('physical_line')
1802 options.logical_checks = self.get_checks('logical_line')
1803 options.ast_checks = self.get_checks('tree')
1804 self.init_report()
1805
1806 def init_report(self, reporter=None):
1807 """Initialize the report instance."""
1808 self.options.report = (reporter or self.options.reporter)(self.options)
1809 return self.options.report
1810
1811 def check_files(self, paths=None):
1812 """Run all checks on the paths."""
1813 if paths is None:
1814 paths = self.paths
1815 report = self.options.report
1816 runner = self.runner
1817 report.start()
1818 try:
1819 for path in paths:
1820 if os.path.isdir(path):
1821 self.input_dir(path)
1822 elif not self.excluded(path):
1823 runner(path)
1824 except KeyboardInterrupt:
1825 print('... stopped')
1826 report.stop()
1827 return report
1828
1829 def input_file(self, filename, lines=None, expected=None, line_offset=0):
1830 """Run all checks on a Python source file."""
1831 if self.options.verbose:
1832 print('checking %s' % filename)
1833 fchecker = self.checker_class(
1834 filename, lines=lines, options=self.options)
1835 return fchecker.check_all(expected=expected, line_offset=line_offset)
1836
1837 def input_dir(self, dirname):
1838 """Check all files in this directory and all subdirectories."""
1839 dirname = dirname.rstrip('/')
1840 if self.excluded(dirname):
1841 return 0
1842 counters = self.options.report.counters
1843 verbose = self.options.verbose
1844 filepatterns = self.options.filename
1845 runner = self.runner
1846 for root, dirs, files in os.walk(dirname):
1847 if verbose:
1848 print('directory ' + root)
1849 counters['directories'] += 1
1850 for subdir in sorted(dirs):
1851 if self.excluded(subdir, root):
1852 dirs.remove(subdir)
1853 for filename in sorted(files):
1854 # contain a pattern that matches?
1855 if ((filename_match(filename, filepatterns) and
1856 not self.excluded(filename, root))):
1857 runner(os.path.join(root, filename))
1858
1859 def excluded(self, filename, parent=None):
1860 """
1861 Check if options.exclude contains a pattern that matches filename.
1862 """
1863 if not self.options.exclude:
1864 return False
1865 basename = os.path.basename(filename)
1866 if filename_match(basename, self.options.exclude):
1867 return True
1868 if parent:
1869 filename = os.path.join(parent, filename)
1870 return filename_match(filename, self.options.exclude)
1871
1872 def ignore_code(self, code):
1873 """
1874 Check if the error code should be ignored.
1875
1876 If 'options.select' contains a prefix of the error code,
1877 return False. Else, if 'options.ignore' contains a prefix of
1878 the error code, return True.
1879 """
1880 return (code.startswith(self.options.ignore) and
1881 not code.startswith(self.options.select))
1882
1883 def get_checks(self, argument_name):
1884 """
1885 Find all globally visible functions where the first argument name
1886 starts with argument_name and which contain selected tests.
1887 """
1888 checks = []
1889 for check, attrs in _checks[argument_name].items():
1890 (codes, args) = attrs
1891 if any(not (code and self.ignore_code(code)) for code in codes):
1892 checks.append((check.__name__, check, args))
1893 return sorted(checks)
1894
1895
1896 def get_parser(prog='pep8', version=__version__):
1897 parser = OptionParser(prog=prog, version=version,
1898 usage="%prog [options] input ...")
1899 parser.config_options = [
1900 'exclude', 'filename', 'select', 'ignore', 'max-line-length',
1901 'hang-closing', 'count', 'format', 'quiet', 'show-pep8',
1902 'show-source', 'statistics', 'verbose']
1903 parser.add_option('-v', '--verbose', default=0, action='count',
1904 help="print status messages, or debug with -vv")
1905 parser.add_option('-q', '--quiet', default=0, action='count',
1906 help="report only file names, or nothing with -qq")
1907 parser.add_option('-r', '--repeat', default=True, action='store_true',
1908 help="(obsolete) show all occurrences of the same error")
1909 parser.add_option('--first', action='store_false', dest='repeat',
1910 help="show first occurrence of each error")
1911 parser.add_option('--exclude', metavar='patterns', default=DEFAULT_EXCLUDE,
1912 help="exclude files or directories which match these "
1913 "comma separated patterns (default: %default)")
1914 parser.add_option('--filename', metavar='patterns', default='*.py',
1915 help="when parsing directories, only check filenames "
1916 "matching these comma separated patterns "
1917 "(default: %default)")
1918 parser.add_option('--select', metavar='errors', default='',
1919 help="select errors and warnings (e.g. E,W6)")
1920 parser.add_option('--ignore', metavar='errors', default='',
1921 help="skip errors and warnings (e.g. E4,W)")
1922 parser.add_option('--show-source', action='store_true',
1923 help="show source code for each error")
1924 parser.add_option('--show-pep8', action='store_true',
1925 help="show text of PEP 8 for each error "
1926 "(implies --first)")
1927 parser.add_option('--statistics', action='store_true',
1928 help="count errors and warnings")
1929 parser.add_option('--count', action='store_true',
1930 help="print total number of errors and warnings "
1931 "to standard error and set exit code to 1 if "
1932 "total is not null")
1933 parser.add_option('--max-line-length', type='int', metavar='n',
1934 default=MAX_LINE_LENGTH,
1935 help="set maximum allowed line length "
1936 "(default: %default)")
1937 parser.add_option('--hang-closing', action='store_true',
1938 help="hang closing bracket instead of matching "
1939 "indentation of opening bracket's line")
1940 parser.add_option('--format', metavar='format', default='default',
1941 help="set the error format [default|pylint|<custom>]")
1942 parser.add_option('--diff', action='store_true',
1943 help="report only lines changed according to the "
1944 "unified diff received on STDIN")
1945 group = parser.add_option_group("Testing Options")
1946 if os.path.exists(TESTSUITE_PATH):
1947 group.add_option('--testsuite', metavar='dir',
1948 help="run regression tests from dir")
1949 group.add_option('--doctest', action='store_true',
1950 help="run doctest on myself")
1951 group.add_option('--benchmark', action='store_true',
1952 help="measure processing speed")
1953 return parser
1954
1955
1956 def read_config(options, args, arglist, parser):
1957 """Read both user configuration and local configuration."""
1958 config = RawConfigParser()
1959
1960 user_conf = options.config
1961 if user_conf and os.path.isfile(user_conf):
1962 if options.verbose:
1963 print('user configuration: %s' % user_conf)
1964 config.read(user_conf)
1965
1966 parent = tail = args and os.path.abspath(os.path.commonprefix(args))
1967 while tail:
1968 if config.read([os.path.join(parent, fn) for fn in PROJECT_CONFIG]):
1969 if options.verbose:
1970 print('local configuration: in %s' % parent)
1971 break
1972 parent, tail = os.path.split(parent)
1973
1974 pep8_section = parser.prog
1975 if config.has_section(pep8_section):
1976 option_list = dict([(o.dest, o.type or o.action)
1977 for o in parser.option_list])
1978
1979 # First, read the default values
1980 new_options, _ = parser.parse_args([])
1981
1982 # Second, parse the configuration
1983 for opt in config.options(pep8_section):
1984 if options.verbose > 1:
1985 print(" %s = %s" % (opt, config.get(pep8_section, opt)))
1986 if opt.replace('_', '-') not in parser.config_options:
1987 print("Unknown option: '%s'\n not in [%s]" %
1988 (opt, ' '.join(parser.config_options)))
1989 sys.exit(1)
1990 normalized_opt = opt.replace('-', '_')
1991 opt_type = option_list[normalized_opt]
1992 if opt_type in ('int', 'count'):
1993 value = config.getint(pep8_section, opt)
1994 elif opt_type == 'string':
1995 value = config.get(pep8_section, opt)
1996 else:
1997 assert opt_type in ('store_true', 'store_false')
1998 value = config.getboolean(pep8_section, opt)
1999 setattr(new_options, normalized_opt, value)
2000
2001 # Third, overwrite with the command-line options
2002 options, _ = parser.parse_args(arglist, values=new_options)
2003 options.doctest = options.testsuite = False
2004 return options
2005
2006
2007 def process_options(arglist=None, parse_argv=False, config_file=None,
2008 parser=None):
2009 """Process options passed either via arglist or via command line args."""
2010 if not arglist and not parse_argv:
2011 # Don't read the command line if the module is used as a library.
2012 arglist = []
2013 if not parser:
2014 parser = get_parser()
2015 if not parser.has_option('--config'):
2016 if config_file is True:
2017 config_file = DEFAULT_CONFIG
2018 group = parser.add_option_group("Configuration", description=(
2019 "The project options are read from the [%s] section of the "
2020 "tox.ini file or the setup.cfg file located in any parent folder "
2021 "of the path(s) being processed. Allowed options are: %s." %
2022 (parser.prog, ', '.join(parser.config_options))))
2023 group.add_option('--config', metavar='path', default=config_file,
2024 help="user config file location (default: %default)")
2025 options, args = parser.parse_args(arglist)
2026 options.reporter = None
2027
2028 if options.ensure_value('testsuite', False):
2029 args.append(options.testsuite)
2030 elif not options.ensure_value('doctest', False):
2031 if parse_argv and not args:
2032 if options.diff or any(os.path.exists(name)
2033 for name in PROJECT_CONFIG):
2034 args = ['.']
2035 else:
2036 parser.error('input not specified')
2037 options = read_config(options, args, arglist, parser)
2038 options.reporter = parse_argv and options.quiet == 1 and FileReport
2039
2040 options.filename = options.filename and options.filename.split(',')
2041 options.exclude = options.exclude.split(',')
2042 options.select = options.select and options.select.split(',')
2043 options.ignore = options.ignore and options.ignore.split(',')
2044
2045 if options.diff:
2046 options.reporter = DiffReport
2047 stdin = stdin_get_value()
2048 options.selected_lines = parse_udiff(stdin, options.filename, args[0])
2049 args = sorted(options.selected_lines)
2050
2051 return options, args
2052
2053
2054 def _main():
2055 """Parse options and run checks on Python source."""
2056 pep8style = StyleGuide(parse_argv=True, config_file=True)
2057 options = pep8style.options
2058 if options.doctest or options.testsuite:
2059 from testsuite.support import run_tests
2060 report = run_tests(pep8style)
2061 else:
2062 report = pep8style.check_files()
2063 if options.statistics:
2064 report.print_statistics()
2065 if options.benchmark:
2066 report.print_benchmark()
2067 if options.testsuite and not options.quiet:
2068 report.print_results()
2069 if report.total_errors:
2070 if options.count:
2071 sys.stderr.write(str(report.total_errors) + '\n')
2072 sys.exit(1)
2073
2074 if __name__ == '__main__':
2075 _main()

eric ide

mercurial