eric6/Plugins/CheckerPlugins/CodeStyleChecker/pycodestyle.py

changeset 6942
2602857055c5
parent 6733
519422827ace
child 7360
9190402e4505
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 # pycodestyle.py - Check Python source code formatting, according to
5 # PEP 8
6 #
7 # Copyright (C) 2006-2009 Johann C. Rocholl <johann@rocholl.net>
8 # Copyright (C) 2009-2014 Florent Xicluna <florent.xicluna@gmail.com>
9 # Copyright (C) 2014-2016 Ian Lee <ianlee1521@gmail.com>
10 #
11 # Permission is hereby granted, free of charge, to any person
12 # obtaining a copy of this software and associated documentation files
13 # (the "Software"), to deal in the Software without restriction,
14 # including without limitation the rights to use, copy, modify, merge,
15 # publish, distribute, sublicense, and/or sell copies of the Software,
16 # and to permit persons to whom the Software is furnished to do so,
17 # subject to the following conditions:
18 #
19 # The above copyright notice and this permission notice shall be
20 # included in all copies or substantial portions of the Software.
21 #
22 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
26 # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
27 # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28 # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 # SOFTWARE.
30
31 r"""
32 Check Python source code formatting, according to PEP 8.
33
34 For usage and a list of options, try this:
35 $ python pycodestyle.py -h
36
37 This program and its regression test suite live here:
38 https://github.com/pycqa/pycodestyle
39
40 Groups of errors and warnings:
41 E errors
42 W warnings
43 100 indentation
44 200 whitespace
45 300 blank lines
46 400 imports
47 500 line length
48 600 deprecation
49 700 statements
50 900 syntax error
51 """
52 from __future__ import with_statement
53
54 #
55 # This is a modified version to make the original pycodestyle.py better
56 # suitable for being called from within the eric6 IDE. The modifications
57 # are as follows:
58 #
59 # - made messages translatable via Qt
60 # - added code for eric6 integration
61 #
62 # Copyright (c) 2011 - 2019 Detlev Offenbach <detlev@die-offenbachs.de>
63 #
64
65 import inspect
66 import keyword
67 import os
68 import re
69 import sys
70 import time
71 import tokenize
72 import warnings
73 import bisect
74
75 try:
76 from functools import lru_cache
77 except ImportError:
78 def lru_cache(maxsize=128): # noqa as it's a fake implementation.
79 """Does not really need a real a lru_cache, it's just
80 optimization, so let's just do nothing here. Python 3.2+ will
81 just get better performances, time to upgrade?
82 """
83 return lambda function: function
84
85 from fnmatch import fnmatch
86 from optparse import OptionParser
87
88 try:
89 from configparser import RawConfigParser
90 from io import TextIOWrapper
91 except ImportError:
92 from ConfigParser import RawConfigParser # __IGNORE_WARNING__
93
94 __version__ = '2.5.0-eric'
95
96 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox'
97 DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503,W504'
98 try:
99 if sys.platform == 'win32':
100 USER_CONFIG = os.path.expanduser(r'~\.pycodestyle')
101 else:
102 USER_CONFIG = os.path.join(
103 os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'),
104 'pycodestyle'
105 )
106 except ImportError:
107 USER_CONFIG = None
108
109 PROJECT_CONFIG = ('setup.cfg', 'tox.ini')
110 TESTSUITE_PATH = os.path.join(os.path.dirname(__file__), 'testsuite')
111 MAX_LINE_LENGTH = 79
112 # Number of blank lines between various code parts.
113 BLANK_LINES_CONFIG = {
114 # Top level class and function.
115 'top_level': 2,
116 # Methods and nested class and function.
117 'method': 1,
118 }
119 MAX_DOC_LENGTH = 72
120 REPORT_FORMAT = {
121 'default': '%(path)s:%(row)d:%(col)d: %(code)s %(text)s',
122 'pylint': '%(path)s:%(row)d: [%(code)s] %(text)s',
123 }
124
125 PyCF_ONLY_AST = 1024
126 SINGLETONS = frozenset(['False', 'None', 'True'])
127 KEYWORDS = frozenset(keyword.kwlist + ['print', 'async']) - SINGLETONS
128 UNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-'])
129 ARITHMETIC_OP = frozenset(['**', '*', '/', '//', '+', '-'])
130 WS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%'])
131 # Warn for -> function annotation operator in py3.5+ (issue 803)
132 FUNCTION_RETURN_ANNOTATION_OP = ['->'] if sys.version_info >= (3, 5) else []
133 WS_NEEDED_OPERATORS = frozenset([
134 '**=', '*=', '/=', '//=', '+=', '-=', '!=', '<>', '<', '>',
135 '%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '='] +
136 FUNCTION_RETURN_ANNOTATION_OP)
137 WHITESPACE = frozenset(' \t')
138 NEWLINE = frozenset([tokenize.NL, tokenize.NEWLINE])
139 SKIP_TOKENS = NEWLINE.union([tokenize.INDENT, tokenize.DEDENT])
140 # ERRORTOKEN is triggered by backticks in Python 3
141 SKIP_COMMENTS = SKIP_TOKENS.union([tokenize.COMMENT, tokenize.ERRORTOKEN])
142 BENCHMARK_KEYS = ['directories', 'files', 'logical lines', 'physical lines']
143
144 INDENT_REGEX = re.compile(r'([ \t]*)')
145 RAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,')
146 RERAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,.*,\s*\w+\s*$')
147 ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b')
148 DOCSTRING_REGEX = re.compile(r'u?r?["\']')
149 EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[\[({] | [\]}),;:]')
150 WHITESPACE_AFTER_COMMA_REGEX = re.compile(r'[,;:]\s*(?: |\t)')
151 COMPARE_SINGLETON_REGEX = re.compile(r'(\bNone|\bFalse|\bTrue)?\s*([=!]=)'
152 r'\s*(?(1)|(None|False|True))\b')
153 COMPARE_NEGATIVE_REGEX = re.compile(r'\b(not)\s+[^][)(}{ ]+\s+(in|is)\s')
154 COMPARE_TYPE_REGEX = re.compile(r'(?:[=!]=|is(?:\s+not)?)\s*type(?:s.\w+Type'
155 r'|\s*\(\s*([^)]*[^ )])\s*\))')
156 KEYWORD_REGEX = re.compile(r'(\s*)\b(?:%s)\b(\s*)' % r'|'.join(KEYWORDS))
157 OPERATOR_REGEX = re.compile(r'(?:[^,\s])(\s*)(?:[-+*/|!<=>%&^]+)(\s*)')
158 LAMBDA_REGEX = re.compile(r'\blambda\b')
159 HUNK_REGEX = re.compile(r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$')
160 STARTSWITH_DEF_REGEX = re.compile(r'^(async\s+def|def)\b')
161 STARTSWITH_TOP_LEVEL_REGEX = re.compile(r'^(async\s+def\s+|def\s+|class\s+|@)')
162 STARTSWITH_INDENT_STATEMENT_REGEX = re.compile(
163 r'^\s*({0})\b'.format('|'.join(s.replace(' ', r'\s+') for s in (
164 'def', 'async def',
165 'for', 'async for',
166 'if', 'elif', 'else',
167 'try', 'except', 'finally',
168 'with', 'async with',
169 'class',
170 'while',
171 )))
172 )
173 DUNDER_REGEX = re.compile(r'^__([^\s]+)__ = ')
174
175 _checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
176
177
178 def _get_parameters(function):
179 if sys.version_info >= (3, 3):
180 return [parameter.name
181 for parameter
182 in inspect.signature(function).parameters.values()
183 if parameter.kind == parameter.POSITIONAL_OR_KEYWORD]
184 else:
185 return inspect.getargspec(function)[0]
186
187
188 def register_check(check, codes=None):
189 """Register a new check object."""
190 def _add_check(check, kind, codes, args):
191 if check in _checks[kind]:
192 _checks[kind][check][0].extend(codes or [])
193 else:
194 _checks[kind][check] = (codes or [''], args)
195 if inspect.isfunction(check):
196 args = _get_parameters(check)
197 if args and args[0] in ('physical_line', 'logical_line'):
198 if codes is None:
199 codes = ERRORCODE_REGEX.findall(check.__doc__ or '')
200 _add_check(check, args[0], codes, args)
201 elif inspect.isclass(check):
202 if _get_parameters(check.__init__)[:2] == ['self', 'tree']:
203 _add_check(check, 'tree', codes, None)
204 return check
205
206
207 ########################################################################
208 # Plugins (check functions) for physical lines
209 ########################################################################
210
211 @register_check
212 def tabs_or_spaces(physical_line, indent_char):
213 r"""Never mix tabs and spaces.
214
215 The most popular way of indenting Python is with spaces only. The
216 second-most popular way is with tabs only. Code indented with a
217 mixture of tabs and spaces should be converted to using spaces
218 exclusively. When invoking the Python command line interpreter with
219 the -t option, it issues warnings about code that illegally mixes
220 tabs and spaces. When using -tt these warnings become errors.
221 These options are highly recommended!
222
223 Okay: if a == 0:\n a = 1\n b = 1
224 E101: if a == 0:\n a = 1\n\tb = 1
225 """
226 indent = INDENT_REGEX.match(physical_line).group(1)
227 for offset, char in enumerate(indent):
228 if char != indent_char:
229 return offset, "E101 indentation contains mixed spaces and tabs"
230
231
232 @register_check
233 def tabs_obsolete(physical_line):
234 r"""On new projects, spaces-only are strongly recommended over tabs.
235
236 Okay: if True:\n return
237 W191: if True:\n\treturn
238 """
239 indent = INDENT_REGEX.match(physical_line).group(1)
240 if '\t' in indent:
241 return indent.index('\t'), "W191 indentation contains tabs"
242
243
244 @register_check
245 def trailing_whitespace(physical_line):
246 r"""Trailing whitespace is superfluous.
247
248 The warning returned varies on whether the line itself is blank,
249 for easier filtering for those who want to indent their blank lines.
250
251 Okay: spam(1)\n#
252 W291: spam(1) \n#
253 W293: class Foo(object):\n \n bang = 12
254 """
255 physical_line = physical_line.rstrip('\n') # chr(10), newline
256 physical_line = physical_line.rstrip('\r') # chr(13), carriage return
257 physical_line = physical_line.rstrip('\x0c') # chr(12), form feed, ^L
258 stripped = physical_line.rstrip(' \t\v')
259 if physical_line != stripped:
260 if stripped:
261 return len(stripped), "W291 trailing whitespace"
262 else:
263 return 0, "W293 blank line contains whitespace"
264
265
266 @register_check
267 def trailing_blank_lines(physical_line, lines, line_number, total_lines):
268 r"""Trailing blank lines are superfluous.
269
270 Okay: spam(1)
271 W391: spam(1)\n
272
273 However the last line should end with a new line (warning W292).
274 """
275 if line_number == total_lines:
276 stripped_last_line = physical_line.rstrip()
277 if physical_line and not stripped_last_line:
278 return 0, "W391 blank line at end of file"
279 if stripped_last_line == physical_line:
280 return len(lines[-1]), "W292 no newline at end of file"
281
282
283 @register_check
284 def maximum_line_length(physical_line, max_line_length, multiline,
285 line_number, noqa):
286 r"""Limit all lines to a maximum of 79 characters.
287
288 There are still many devices around that are limited to 80 character
289 lines; plus, limiting windows to 80 characters makes it possible to
290 have several windows side-by-side. The default wrapping on such
291 devices looks ugly. Therefore, please limit all lines to a maximum
292 of 79 characters. For flowing long blocks of text (docstrings or
293 comments), limiting the length to 72 characters is recommended.
294
295 Reports error E501.
296 """
297 line = physical_line.rstrip()
298 length = len(line)
299 if length > max_line_length and not noqa:
300 # Special case: ignore long shebang lines.
301 if line_number == 1 and line.startswith('#!'):
302 return
303 # Special case for long URLs in multi-line docstrings or
304 # comments, but still report the error when the 72 first chars
305 # are whitespaces.
306 chunks = line.split()
307 if ((len(chunks) == 1 and multiline) or
308 (len(chunks) == 2 and chunks[0] == '#')) and \
309 len(line) - len(chunks[-1]) < max_line_length - 7:
310 return
311 if hasattr(line, 'decode'): # Python 2
312 # The line could contain multi-byte characters
313 try:
314 length = len(line.decode('utf-8'))
315 except UnicodeError:
316 pass
317 if length > max_line_length:
318 return (max_line_length, "E501 line too long "
319 "(%d > %d characters)" % (length, max_line_length),
320 length, max_line_length)
321
322
323 ########################################################################
324 # Plugins (check functions) for logical lines
325 ########################################################################
326
327
328 @register_check
329 def blank_lines(logical_line, blank_lines, indent_level, line_number,
330 blank_before, previous_logical,
331 previous_unindented_logical_line, previous_indent_level,
332 lines):
333 r"""Separate top-level function and class definitions with two blank
334 lines.
335
336 Method definitions inside a class are separated by a single blank
337 line.
338
339 Extra blank lines may be used (sparingly) to separate groups of
340 related functions. Blank lines may be omitted between a bunch of
341 related one-liners (e.g. a set of dummy implementations).
342
343 Use blank lines in functions, sparingly, to indicate logical
344 sections.
345
346 Okay: def a():\n pass\n\n\ndef b():\n pass
347 Okay: def a():\n pass\n\n\nasync def b():\n pass
348 Okay: def a():\n pass\n\n\n# Foo\n# Bar\n\ndef b():\n pass
349 Okay: default = 1\nfoo = 1
350 Okay: classify = 1\nfoo = 1
351
352 E301: class Foo:\n b = 0\n def bar():\n pass
353 E302: def a():\n pass\n\ndef b(n):\n pass
354 E302: def a():\n pass\n\nasync def b(n):\n pass
355 E303: def a():\n pass\n\n\n\ndef b(n):\n pass
356 E304: @decorator\n\ndef a():\n pass
357 E305: def a():\n pass\na()
358 E306: def a():\n def b():\n pass\n def c():\n pass
359 E307: def a():\n def b():\n pass\n\n\n def c():\n pass
360 E308: def a():\n\n\n\n pass
361 """
362 top_level_lines = BLANK_LINES_CONFIG['top_level']
363 method_lines = BLANK_LINES_CONFIG['method']
364
365 if line_number < top_level_lines + 1 and not previous_logical:
366 return # Don't expect blank lines before the first line
367 if previous_logical.startswith('@'):
368 if blank_lines:
369 yield 0, "E304 blank lines found after function decorator"
370 elif (blank_lines > top_level_lines or
371 (indent_level and blank_lines == method_lines + 1)
372 ):
373 if indent_level:
374 if previous_logical.strip().startswith(('def ', 'class ')):
375 yield (0, "E308 too many blank lines (%d)", blank_lines)
376 else:
377 yield (0, "E307 too many blank lines (%d) in a nested "
378 "scope, expected %d", blank_lines, method_lines)
379 else:
380 yield (0, "E303 too many blank lines (%d), expected %d",
381 blank_lines, top_level_lines)
382 elif STARTSWITH_TOP_LEVEL_REGEX.match(logical_line):
383 # If this is a one-liner (i.e. the next line is not more
384 # indented), and the previous line is also not deeper
385 # (it would be better to check if the previous line is part
386 # of another def/class at the same level), don't require blank
387 # lines around this.
388 prev_line = lines[line_number - 2] if line_number >= 2 else ''
389 next_line = lines[line_number] if line_number < len(lines) else ''
390 if (expand_indent(prev_line) <= indent_level and
391 expand_indent(next_line) <= indent_level):
392 return
393 if indent_level:
394 if not (blank_before == method_lines or
395 previous_indent_level < indent_level or
396 DOCSTRING_REGEX.match(previous_logical)
397 ):
398 ancestor_level = indent_level
399 nested = False
400 # Search backwards for a def ancestor or tree root
401 # (top level).
402 for line in lines[line_number - top_level_lines::-1]:
403 if line.strip() and expand_indent(line) < ancestor_level:
404 ancestor_level = expand_indent(line)
405 nested = line.lstrip().startswith('def ')
406 if nested or ancestor_level == 0:
407 break
408 if nested:
409 yield (0, "E306 expected %s blank lines before a "
410 "nested definition, found %d", method_lines,
411 blank_before)
412 else:
413 yield (0, "E301 expected %s blank lines, found %d",
414 method_lines, blank_before)
415 elif blank_before != top_level_lines:
416 yield (0, "E302 expected %s blank lines, found %d",
417 top_level_lines, blank_before)
418 elif (logical_line and
419 not indent_level and
420 blank_before != top_level_lines and
421 previous_unindented_logical_line.startswith(('def ', 'class '))
422 ):
423 yield (0, "E305 expected %s blank lines after " \
424 "class or function definition, found %d",
425 top_level_lines, blank_before)
426
427
428 @register_check
429 def extraneous_whitespace(logical_line):
430 r"""Avoid extraneous whitespace.
431
432 Avoid extraneous whitespace in these situations:
433 - Immediately inside parentheses, brackets or braces.
434 - Immediately before a comma, semicolon, or colon.
435
436 Okay: spam(ham[1], {eggs: 2})
437 E201: spam( ham[1], {eggs: 2})
438 E201: spam(ham[ 1], {eggs: 2})
439 E201: spam(ham[1], { eggs: 2})
440 E202: spam(ham[1], {eggs: 2} )
441 E202: spam(ham[1 ], {eggs: 2})
442 E202: spam(ham[1], {eggs: 2 })
443
444 E203: if x == 4: print x, y; x, y = y , x
445 E203: if x == 4: print x, y ; x, y = y, x
446 E203: if x == 4 : print x, y; x, y = y, x
447 """
448 line = logical_line
449 for match in EXTRANEOUS_WHITESPACE_REGEX.finditer(line):
450 text = match.group()
451 char = text.strip()
452 found = match.start()
453 if text == char + ' ':
454 # assert char in '([{'
455 yield found + 1, "E201 whitespace after '%s'", char
456 elif line[found - 1] != ',':
457 code = ('E202' if char in '}])' else 'E203') # if char in ',;:'
458 yield found, "%s whitespace before '%s'" % (code, char), char
459
460
461 @register_check
462 def whitespace_around_keywords(logical_line):
463 r"""Avoid extraneous whitespace around keywords.
464
465 Okay: True and False
466 E271: True and False
467 E272: True and False
468 E273: True and\tFalse
469 E274: True\tand False
470 """
471 for match in KEYWORD_REGEX.finditer(logical_line):
472 before, after = match.groups()
473
474 if '\t' in before:
475 yield match.start(1), "E274 tab before keyword"
476 elif len(before) > 1:
477 yield match.start(1), "E272 multiple spaces before keyword"
478
479 if '\t' in after:
480 yield match.start(2), "E273 tab after keyword"
481 elif len(after) > 1:
482 yield match.start(2), "E271 multiple spaces after keyword"
483
484
485 @register_check
486 def missing_whitespace_after_import_keyword(logical_line):
487 r"""Multiple imports in form from x import (a, b, c) should have
488 space between import statement and parenthesised name list.
489
490 Okay: from foo import (bar, baz)
491 E275: from foo import(bar, baz)
492 E275: from importable.module import(bar, baz)
493 """
494 line = logical_line
495 indicator = ' import('
496 if line.startswith('from '):
497 found = line.find(indicator)
498 if -1 < found:
499 pos = found + len(indicator) - 1
500 yield pos, "E275 missing whitespace after keyword"
501
502
503 @register_check
504 def missing_whitespace(logical_line):
505 r"""Each comma, semicolon or colon should be followed by whitespace.
506
507 Okay: [a, b]
508 Okay: (3,)
509 Okay: a[1:4]
510 Okay: a[:4]
511 Okay: a[1:]
512 Okay: a[1:4:2]
513 E231: ['a','b']
514 E231: foo(bar,baz)
515 E231: [{'a':'b'}]
516 """
517 line = logical_line
518 for index in range(len(line) - 1):
519 char = line[index]
520 if char in ',;:' and line[index + 1] not in WHITESPACE:
521 before = line[:index]
522 if char == ':' and before.count('[') > before.count(']') and \
523 before.rfind('{') < before.rfind('['):
524 continue # Slice syntax, no space required
525 if char == ',' and line[index + 1] == ')':
526 continue # Allow tuple with only one element: (3,)
527 yield index, "E231 missing whitespace after '%s'", char
528
529
530 @register_check
531 def indentation(logical_line, previous_logical, indent_char,
532 indent_level, previous_indent_level):
533 r"""Use 4 spaces per indentation level.
534
535 For really old code that you don't want to mess up, you can continue
536 to use 8-space tabs.
537
538 Okay: a = 1
539 Okay: if a == 0:\n a = 1
540 E111: a = 1
541 E114: # a = 1
542
543 Okay: for item in items:\n pass
544 E112: for item in items:\npass
545 E115: for item in items:\n# Hi\n pass
546
547 Okay: a = 1\nb = 2
548 E113: a = 1\n b = 2
549 E116: a = 1\n # b = 2
550 """
551 c = 0 if logical_line else 3
552 tmpl = "E11%d %s" if logical_line else "E11%d %s (comment)"
553 if indent_level % 4:
554 yield 0, tmpl % (1 + c, "indentation is not a multiple of four")
555 indent_expect = previous_logical.endswith(':')
556 if indent_expect and indent_level <= previous_indent_level:
557 yield 0, tmpl % (2 + c, "expected an indented block")
558 elif not indent_expect and indent_level > previous_indent_level:
559 yield 0, tmpl % (3 + c, "unexpected indentation")
560
561 expected_indent_level = previous_indent_level + 4
562 if indent_expect and indent_level > expected_indent_level:
563 yield 0, tmpl % (7, 'over-indented')
564
565
566 @register_check
567 def continued_indentation(logical_line, tokens, indent_level, hang_closing,
568 indent_char, noqa, verbose):
569 r"""Continuation lines indentation.
570
571 Continuation lines should align wrapped elements either vertically
572 using Python's implicit line joining inside parentheses, brackets
573 and braces, or using a hanging indent.
574
575 When using a hanging indent these considerations should be applied:
576 - there should be no arguments on the first line, and
577 - further indentation should be used to clearly distinguish itself
578 as a continuation line.
579
580 Okay: a = (\n)
581 E123: a = (\n )
582
583 Okay: a = (\n 42)
584 E121: a = (\n 42)
585 E122: a = (\n42)
586 E123: a = (\n 42\n )
587 E124: a = (24,\n 42\n)
588 E125: if (\n b):\n pass
589 E126: a = (\n 42)
590 E127: a = (24,\n 42)
591 E128: a = (24,\n 42)
592 E129: if (a or\n b):\n pass
593 E131: a = (\n 42\n 24)
594 """
595 first_row = tokens[0][2][0]
596 nrows = 1 + tokens[-1][2][0] - first_row
597 if noqa or nrows == 1:
598 return
599
600 # indent_next tells us whether the next block is indented; assuming
601 # that it is indented by 4 spaces, then we should not allow 4-space
602 # indents on the final continuation line; in turn, some other
603 # indents are allowed to have an extra 4 spaces.
604 indent_next = logical_line.endswith(':')
605
606 row = depth = 0
607 valid_hangs = (4,) if indent_char != '\t' else (4, 8)
608 # remember how many brackets were opened on each line
609 parens = [0] * nrows
610 # relative indents of physical lines
611 rel_indent = [0] * nrows
612 # for each depth, collect a list of opening rows
613 open_rows = [[0]]
614 # for each depth, memorize the hanging indentation
615 hangs = [None]
616 # visual indents
617 indent_chances = {}
618 last_indent = tokens[0][2]
619 visual_indent = None
620 last_token_multiline = False
621 # for each depth, memorize the visual indent column
622 indent = [last_indent[1]]
623 if verbose >= 3:
624 print(">>> " + tokens[0][4].rstrip())
625
626 for token_type, text, start, end, line in tokens:
627
628 newline = row < start[0] - first_row
629 if newline:
630 row = start[0] - first_row
631 newline = not last_token_multiline and token_type not in NEWLINE
632
633 if newline:
634 # this is the beginning of a continuation line.
635 last_indent = start
636 if verbose >= 3:
637 print("... " + line.rstrip())
638
639 # record the initial indent.
640 rel_indent[row] = expand_indent(line) - indent_level
641
642 # identify closing bracket
643 close_bracket = (token_type == tokenize.OP and text in ']})')
644
645 # is the indent relative to an opening bracket line?
646 for open_row in reversed(open_rows[depth]):
647 hang = rel_indent[row] - rel_indent[open_row]
648 hanging_indent = hang in valid_hangs
649 if hanging_indent:
650 break
651 if hangs[depth]:
652 hanging_indent = (hang == hangs[depth])
653 # is there any chance of visual indent?
654 visual_indent = (not close_bracket and hang > 0 and
655 indent_chances.get(start[1]))
656
657 if close_bracket and indent[depth]:
658 # closing bracket for visual indent
659 if start[1] != indent[depth]:
660 yield (start, "E124 closing bracket does not match "
661 "visual indentation")
662 elif close_bracket and not hang:
663 # closing bracket matches indentation of opening
664 # bracket's line
665 if hang_closing:
666 yield start, "E133 closing bracket is missing indentation"
667 elif indent[depth] and start[1] < indent[depth]:
668 if visual_indent is not True:
669 # visual indent is broken
670 yield (start, "E128 continuation line "
671 "under-indented for visual indent")
672 elif hanging_indent or (indent_next and rel_indent[row] == 8):
673 # hanging indent is verified
674 if close_bracket and not hang_closing:
675 yield (start, "E123 closing bracket does not match "
676 "indentation of opening bracket's line")
677 hangs[depth] = hang
678 elif visual_indent is True:
679 # visual indent is verified
680 indent[depth] = start[1]
681 elif visual_indent in (text, str):
682 # ignore token lined up with matching one from a
683 # previous line
684 pass
685 else:
686 # indent is broken
687 if hang <= 0:
688 error = "E122", "missing indentation or outdented"
689 elif indent[depth]:
690 error = "E127", "over-indented for visual indent"
691 elif not close_bracket and hangs[depth]:
692 error = "E131", "unaligned for hanging indent"
693 else:
694 hangs[depth] = hang
695 if hang > 4:
696 error = "E126", "over-indented for hanging indent"
697 else:
698 error = "E121", "under-indented for hanging indent"
699 yield start, "%s continuation line %s" % error
700
701 # look for visual indenting
702 if (parens[row] and
703 token_type not in (tokenize.NL, tokenize.COMMENT) and
704 not indent[depth]):
705 indent[depth] = start[1]
706 indent_chances[start[1]] = True
707 if verbose >= 4:
708 print("bracket depth %s indent to %s" % (depth, start[1]))
709 # deal with implicit string concatenation
710 elif (token_type in (tokenize.STRING, tokenize.COMMENT) or
711 text in ('u', 'ur', 'b', 'br')):
712 indent_chances[start[1]] = str
713 # special case for the "if" statement because len("if (") == 4
714 elif not indent_chances and not row and not depth and text == 'if':
715 indent_chances[end[1] + 1] = True
716 elif text == ':' and line[end[1]:].isspace():
717 open_rows[depth].append(row)
718
719 # keep track of bracket depth
720 if token_type == tokenize.OP:
721 if text in '([{':
722 depth += 1
723 indent.append(0)
724 hangs.append(None)
725 if len(open_rows) == depth:
726 open_rows.append([])
727 open_rows[depth].append(row)
728 parens[row] += 1
729 if verbose >= 4:
730 print("bracket depth %s seen, col %s, visual min = %s" %
731 (depth, start[1], indent[depth]))
732 elif text in ')]}' and depth > 0:
733 # parent indents should not be more than this one
734 prev_indent = indent.pop() or last_indent[1]
735 hangs.pop()
736 for d in range(depth):
737 if indent[d] > prev_indent:
738 indent[d] = 0
739 for ind in list(indent_chances):
740 if ind >= prev_indent:
741 del indent_chances[ind]
742 del open_rows[depth + 1:]
743 depth -= 1
744 if depth:
745 indent_chances[indent[depth]] = True
746 for idx in range(row, -1, -1):
747 if parens[idx]:
748 parens[idx] -= 1
749 break
750 assert len(indent) == depth + 1
751 if start[1] not in indent_chances:
752 # allow lining up tokens
753 indent_chances[start[1]] = text
754
755 last_token_multiline = (start[0] != end[0])
756 if last_token_multiline:
757 rel_indent[end[0] - first_row] = rel_indent[row]
758
759 if indent_next and expand_indent(line) == indent_level + 4:
760 pos = (start[0], indent[0] + 4)
761 if visual_indent:
762 code = "E129 visually indented line"
763 else:
764 code = "E125 continuation line"
765 yield pos, "%s with same indent as next logical line" % code
766
767
768 @register_check
769 def whitespace_before_parameters(logical_line, tokens):
770 r"""Avoid extraneous whitespace.
771
772 Avoid extraneous whitespace in the following situations:
773 - before the open parenthesis that starts the argument list of a
774 function call.
775 - before the open parenthesis that starts an indexing or slicing.
776
777 Okay: spam(1)
778 E211: spam (1)
779
780 Okay: dict['key'] = list[index]
781 E211: dict ['key'] = list[index]
782 E211: dict['key'] = list [index]
783 """
784 prev_type, prev_text, __, prev_end, __ = tokens[0]
785 for index in range(1, len(tokens)):
786 token_type, text, start, end, __ = tokens[index]
787 if (token_type == tokenize.OP and
788 text in '([' and
789 start != prev_end and
790 (prev_type == tokenize.NAME or prev_text in '}])') and
791 # Syntax "class A (B):" is allowed, but avoid it
792 (index < 2 or tokens[index - 2][1] != 'class') and
793 # Allow "return (a.foo for a in range(5))"
794 not keyword.iskeyword(prev_text)):
795 yield prev_end, "E211 whitespace before '%s'", text
796 prev_type = token_type
797 prev_text = text
798 prev_end = end
799
800
801 @register_check
802 def whitespace_around_operator(logical_line):
803 r"""Avoid extraneous whitespace around an operator.
804
805 Okay: a = 12 + 3
806 E221: a = 4 + 5
807 E222: a = 4 + 5
808 E223: a = 4\t+ 5
809 E224: a = 4 +\t5
810 """
811 for match in OPERATOR_REGEX.finditer(logical_line):
812 before, after = match.groups()
813
814 if '\t' in before:
815 yield match.start(1), "E223 tab before operator"
816 elif len(before) > 1:
817 yield match.start(1), "E221 multiple spaces before operator"
818
819 if '\t' in after:
820 yield match.start(2), "E224 tab after operator"
821 elif len(after) > 1:
822 yield match.start(2), "E222 multiple spaces after operator"
823
824
825 @register_check
826 def missing_whitespace_around_operator(logical_line, tokens):
827 r"""Surround operators with a single space on either side.
828
829 - Always surround these binary operators with a single space on
830 either side: assignment (=), augmented assignment (+=, -= etc.),
831 comparisons (==, <, >, !=, <=, >=, in, not in, is, is not),
832 Booleans (and, or, not).
833
834 - If operators with different priorities are used, consider adding
835 whitespace around the operators with the lowest priorities.
836
837 Okay: i = i + 1
838 Okay: submitted += 1
839 Okay: x = x * 2 - 1
840 Okay: hypot2 = x * x + y * y
841 Okay: c = (a + b) * (a - b)
842 Okay: foo(bar, key='word', *args, **kwargs)
843 Okay: alpha[:-i]
844
845 E225: i=i+1
846 E225: submitted +=1
847 E225: x = x /2 - 1
848 E225: z = x **y
849 E226: c = (a+b) * (a-b)
850 E226: hypot2 = x*x + y*y
851 E227: c = a|b
852 E228: msg = fmt%(errno, errmsg)
853 """
854 parens = 0
855 need_space = False
856 prev_type = tokenize.OP
857 prev_text = prev_end = None
858 for token_type, text, start, end, line in tokens:
859 if token_type in SKIP_COMMENTS:
860 continue
861 if text in ('(', 'lambda'):
862 parens += 1
863 elif text == ')':
864 parens -= 1
865 if need_space:
866 if start != prev_end:
867 # Found a (probably) needed space
868 if need_space is not True and not need_space[1]:
869 yield (need_space[0],
870 "E225 missing whitespace around operator")
871 need_space = False
872 elif text == '>' and prev_text in ('<', '-'):
873 # Tolerate the "<>" operator, even if running Python 3
874 # Deal with Python 3's annotated return value "->"
875 pass
876 else:
877 if need_space is True or need_space[1]:
878 # A needed trailing space was not found
879 yield prev_end, "E225 missing whitespace around operator"
880 elif prev_text != '**':
881 code, optype = 'E226', 'arithmetic'
882 if prev_text == '%':
883 code, optype = 'E228', 'modulo'
884 elif prev_text not in ARITHMETIC_OP:
885 code, optype = 'E227', 'bitwise or shift'
886 yield (need_space[0], "%s missing whitespace "
887 "around %s operator" % (code, optype))
888 need_space = False
889 elif token_type == tokenize.OP and prev_end is not None:
890 if text == '=' and parens:
891 # Allow keyword args or defaults: foo(bar=None).
892 pass
893 elif text in WS_NEEDED_OPERATORS:
894 need_space = True
895 elif text in UNARY_OPERATORS:
896 # Check if the operator is used as a binary operator
897 # Allow unary operators: -123, -x, +1.
898 # Allow argument unpacking: foo(*args, **kwargs).
899 if (prev_text in '}])' if prev_type == tokenize.OP
900 else prev_text not in KEYWORDS):
901 need_space = None
902 elif text in WS_OPTIONAL_OPERATORS:
903 need_space = None
904
905 if need_space is None:
906 # Surrounding space is optional, but ensure that
907 # trailing space matches opening space
908 need_space = (prev_end, start != prev_end)
909 elif need_space and start == prev_end:
910 # A needed opening space was not found
911 yield prev_end, "E225 missing whitespace around operator"
912 need_space = False
913 prev_type = token_type
914 prev_text = text
915 prev_end = end
916
917
918 @register_check
919 def whitespace_around_comma(logical_line):
920 r"""Avoid extraneous whitespace after a comma or a colon.
921
922 Note: these checks are disabled by default
923
924 Okay: a = (1, 2)
925 E241: a = (1, 2)
926 E242: a = (1,\t2)
927 """
928 line = logical_line
929 for m in WHITESPACE_AFTER_COMMA_REGEX.finditer(line):
930 found = m.start() + 1
931 if '\t' in m.group():
932 yield found, "E242 tab after '%s'", m.group()[0]
933 else:
934 yield found, "E241 multiple spaces after '%s'", m.group()[0]
935
936
937 @register_check
938 def whitespace_around_named_parameter_equals(logical_line, tokens):
939 r"""Don't use spaces around the '=' sign in function arguments.
940
941 Don't use spaces around the '=' sign when used to indicate a
942 keyword argument or a default parameter value, except when
943 using a type annotation.
944
945 Okay: def complex(real, imag=0.0):
946 Okay: return magic(r=real, i=imag)
947 Okay: boolean(a == b)
948 Okay: boolean(a != b)
949 Okay: boolean(a <= b)
950 Okay: boolean(a >= b)
951 Okay: def foo(arg: int = 42):
952 Okay: async def foo(arg: int = 42):
953
954 E251: def complex(real, imag = 0.0):
955 E251: return magic(r = real, i = imag)
956 E252: def complex(real, image: float=0.0):
957 """
958 parens = 0
959 no_space = False
960 require_space = False
961 prev_end = None
962 annotated_func_arg = False
963 in_def = bool(STARTSWITH_DEF_REGEX.match(logical_line))
964
965 message = "E251 unexpected spaces around keyword / parameter equals"
966 missing_message = "E252 missing whitespace around parameter equals"
967
968 for token_type, text, start, end, line in tokens:
969 if token_type == tokenize.NL:
970 continue
971 if no_space:
972 no_space = False
973 if start != prev_end:
974 yield (prev_end, message)
975 if require_space:
976 require_space = False
977 if start == prev_end:
978 yield (prev_end, missing_message)
979 if token_type == tokenize.OP:
980 if text in '([':
981 parens += 1
982 elif text in ')]':
983 parens -= 1
984 elif in_def and text == ':' and parens == 1:
985 annotated_func_arg = True
986 elif parens == 1 and text == ',':
987 annotated_func_arg = False
988 elif parens and text == '=':
989 if annotated_func_arg and parens == 1:
990 require_space = True
991 if start == prev_end:
992 yield (prev_end, missing_message)
993 else:
994 no_space = True
995 if start != prev_end:
996 yield (prev_end, message)
997 if not parens:
998 annotated_func_arg = False
999
1000 prev_end = end
1001
1002
1003 @register_check
1004 def whitespace_before_comment(logical_line, tokens):
1005 r"""Separate inline comments by at least two spaces.
1006
1007 An inline comment is a comment on the same line as a statement.
1008 Inline comments should be separated by at least two spaces from the
1009 statement. They should start with a # and a single space.
1010
1011 Each line of a block comment starts with a # and a single space
1012 (unless it is indented text inside the comment).
1013
1014 Okay: x = x + 1 # Increment x
1015 Okay: x = x + 1 # Increment x
1016 Okay: # Block comment
1017 E261: x = x + 1 # Increment x
1018 E262: x = x + 1 #Increment x
1019 E262: x = x + 1 # Increment x
1020 E265: #Block comment
1021 E266: ### Block comment
1022 """
1023 prev_end = (0, 0)
1024 for token_type, text, start, end, line in tokens:
1025 if token_type == tokenize.COMMENT:
1026 inline_comment = line[:start[1]].strip()
1027 if inline_comment:
1028 if prev_end[0] == start[0] and start[1] < prev_end[1] + 2:
1029 yield (prev_end,
1030 "E261 at least two spaces before inline comment")
1031 symbol, sp, comment = text.partition(' ')
1032 bad_prefix = symbol not in '#:' and (symbol.lstrip('#')[:1] or '#')
1033 if inline_comment:
1034 if bad_prefix or comment[:1] in WHITESPACE:
1035 yield start, "E262 inline comment should start with '# '"
1036 elif bad_prefix and (bad_prefix != '!' or start[0] > 1):
1037 if bad_prefix != '#':
1038 yield start, "E265 block comment should start with '# '"
1039 elif comment:
1040 yield start, "E266 too many leading '#' for block comment"
1041 elif token_type != tokenize.NL:
1042 prev_end = end
1043
1044
1045 @register_check
1046 def imports_on_separate_lines(logical_line):
1047 r"""Place imports on separate lines.
1048
1049 Okay: import os\nimport sys
1050 E401: import sys, os
1051
1052 Okay: from subprocess import Popen, PIPE
1053 Okay: from myclas import MyClass
1054 Okay: from foo.bar.yourclass import YourClass
1055 Okay: import myclass
1056 Okay: import foo.bar.yourclass
1057 """
1058 line = logical_line
1059 if line.startswith('import '):
1060 found = line.find(',')
1061 if -1 < found and ';' not in line[:found]:
1062 yield found, "E401 multiple imports on one line"
1063
1064
1065 @register_check
1066 def module_imports_on_top_of_file(
1067 logical_line, indent_level, checker_state, noqa):
1068 r"""Place imports at the top of the file.
1069
1070 Always put imports at the top of the file, just after any module
1071 comments and docstrings, and before module globals and constants.
1072
1073 Okay: import os
1074 Okay: # this is a comment\nimport os
1075 Okay: '''this is a module docstring'''\nimport os
1076 Okay: r'''this is a module docstring'''\nimport os
1077 Okay:
1078 try:\n\timport x\nexcept ImportError:\n\tpass\nelse:\n\tpass\nimport y
1079 Okay:
1080 try:\n\timport x\nexcept ImportError:\n\tpass\nfinally:\n\tpass\nimport y
1081
1082 E402: a=1\nimport os
1083 E402: 'One string'\n"Two string"\nimport os
1084 E402: a=1\nfrom sys import x
1085
1086 Okay: if x:\n import os
1087 """ # noqa
1088 def is_string_literal(line):
1089 if line[0] in 'uUbB':
1090 line = line[1:]
1091 if line and line[0] in 'rR':
1092 line = line[1:]
1093 return line and (line[0] == '"' or line[0] == "'")
1094
1095 allowed_try_keywords = ('try', 'except', 'else', 'finally')
1096
1097 if indent_level: # Allow imports in conditional statement/function
1098 return
1099 if not logical_line: # Allow empty lines or comments
1100 return
1101 if noqa:
1102 return
1103 line = logical_line
1104 if line.startswith('import ') or line.startswith('from '):
1105 if checker_state.get('seen_non_imports', False):
1106 yield 0, "E402 module level import not at top of file"
1107 elif re.match(DUNDER_REGEX, line):
1108 return
1109 elif any(line.startswith(kw) for kw in allowed_try_keywords):
1110 # Allow try, except, else, finally keywords intermixed with
1111 # imports in order to support conditional importing
1112 return
1113 elif is_string_literal(line):
1114 # The first literal is a docstring, allow it. Otherwise, report
1115 # error.
1116 if checker_state.get('seen_docstring', False):
1117 checker_state['seen_non_imports'] = True
1118 else:
1119 checker_state['seen_docstring'] = True
1120 else:
1121 checker_state['seen_non_imports'] = True
1122
1123
1124 @register_check
1125 def compound_statements(logical_line):
1126 r"""Compound statements (on the same line) are generally
1127 discouraged.
1128
1129 While sometimes it's okay to put an if/for/while with a small body
1130 on the same line, never do this for multi-clause statements.
1131 Also avoid folding such long lines!
1132
1133 Always use a def statement instead of an assignment statement that
1134 binds a lambda expression directly to a name.
1135
1136 Okay: if foo == 'blah':\n do_blah_thing()
1137 Okay: do_one()
1138 Okay: do_two()
1139 Okay: do_three()
1140
1141 E701: if foo == 'blah': do_blah_thing()
1142 E701: for x in lst: total += x
1143 E701: while t < 10: t = delay()
1144 E701: if foo == 'blah': do_blah_thing()
1145 E701: else: do_non_blah_thing()
1146 E701: try: something()
1147 E701: finally: cleanup()
1148 E701: if foo == 'blah': one(); two(); three()
1149 E702: do_one(); do_two(); do_three()
1150 E703: do_four(); # useless semicolon
1151 E704: def f(x): return 2*x
1152 E731: f = lambda x: 2*x
1153 """
1154 line = logical_line
1155 last_char = len(line) - 1
1156 found = line.find(':')
1157 prev_found = 0
1158 counts = {char: 0 for char in '{}[]()'}
1159 while -1 < found < last_char:
1160 update_counts(line[prev_found:found], counts)
1161 if ((counts['{'] <= counts['}'] and # {'a': 1} (dict)
1162 counts['['] <= counts[']'] and # [1:2] (slice)
1163 counts['('] <= counts[')'])): # (annotation)
1164 lambda_kw = LAMBDA_REGEX.search(line, 0, found)
1165 if lambda_kw:
1166 before = line[:lambda_kw.start()].rstrip()
1167 if before[-1:] == '=' and isidentifier(before[:-1].strip()):
1168 yield 0, ("E731 do not assign a lambda expression, use a "
1169 "def")
1170 break
1171 if STARTSWITH_DEF_REGEX.match(line):
1172 yield 0, "E704 multiple statements on one line (def)"
1173 elif STARTSWITH_INDENT_STATEMENT_REGEX.match(line):
1174 yield found, "E701 multiple statements on one line (colon)"
1175 prev_found = found
1176 found = line.find(':', found + 1)
1177 found = line.find(';')
1178 while -1 < found:
1179 if found < last_char:
1180 yield found, "E702 multiple statements on one line (semicolon)"
1181 else:
1182 yield found, "E703 statement ends with a semicolon"
1183 found = line.find(';', found + 1)
1184
1185
1186 @register_check
1187 def explicit_line_join(logical_line, tokens):
1188 r"""Avoid explicit line join between brackets.
1189
1190 The preferred way of wrapping long lines is by using Python's
1191 implied line continuation inside parentheses, brackets and braces.
1192 Long lines can be broken over multiple lines by wrapping expressions
1193 in parentheses. These should be used in preference to using a
1194 backslash for line continuation.
1195
1196 E502: aaa = [123, \\n 123]
1197 E502: aaa = ("bbb " \\n "ccc")
1198
1199 Okay: aaa = [123,\n 123]
1200 Okay: aaa = ("bbb "\n "ccc")
1201 Okay: aaa = "bbb " \\n "ccc"
1202 Okay: aaa = 123 # \\
1203 """
1204 prev_start = prev_end = parens = 0
1205 comment = False
1206 backslash = None
1207 for token_type, text, start, end, line in tokens:
1208 if token_type == tokenize.COMMENT:
1209 comment = True
1210 if start[0] != prev_start and parens and backslash and not comment:
1211 yield backslash, "E502 the backslash is redundant between brackets"
1212 if end[0] != prev_end:
1213 if line.rstrip('\r\n').endswith('\\'):
1214 backslash = (end[0], len(line.splitlines()[-1]) - 1)
1215 else:
1216 backslash = None
1217 prev_start = prev_end = end[0]
1218 else:
1219 prev_start = start[0]
1220 if token_type == tokenize.OP:
1221 if text in '([{':
1222 parens += 1
1223 elif text in ')]}':
1224 parens -= 1
1225
1226
1227 def _is_binary_operator(token_type, text):
1228 is_op_token = token_type == tokenize.OP
1229 is_conjunction = text in ['and', 'or']
1230 # NOTE(sigmavirus24): Previously the not_a_symbol check was executed
1231 # conditionally. Since it is now *always* executed, text may be
1232 # None. In that case we get a TypeError for `text not in str`.
1233 not_a_symbol = text and text not in "()[]{},:.;@=%~"
1234 # The % character is strictly speaking a binary operator, but the
1235 # common usage seems to be to put it next to the format parameters,
1236 # after a line break.
1237 return ((is_op_token or is_conjunction) and not_a_symbol)
1238
1239
1240 def _break_around_binary_operators(tokens):
1241 """Private function to reduce duplication.
1242
1243 This factors out the shared details between
1244 :func:`break_before_binary_operator` and
1245 :func:`break_after_binary_operator`.
1246 """
1247 line_break = False
1248 unary_context = True
1249 # Previous non-newline token types and text
1250 previous_token_type = None
1251 previous_text = None
1252 for token_type, text, start, end, line in tokens:
1253 if token_type == tokenize.COMMENT:
1254 continue
1255 if ('\n' in text or '\r' in text) and token_type != tokenize.STRING:
1256 line_break = True
1257 else:
1258 yield (token_type, text, previous_token_type, previous_text,
1259 line_break, unary_context, start)
1260 unary_context = text in '([{,;'
1261 line_break = False
1262 previous_token_type = token_type
1263 previous_text = text
1264
1265
1266 @register_check
1267 def break_before_binary_operator(logical_line, tokens):
1268 r"""
1269 Avoid breaks before binary operators.
1270
1271 The preferred place to break around a binary operator is after the
1272 operator, not before it.
1273
1274 W503: (width == 0\n + height == 0)
1275 W503: (width == 0\n and height == 0)
1276 W503: var = (1\n & ~2)
1277 W503: var = (1\n / -2)
1278 W503: var = (1\n + -1\n + -2)
1279
1280 Okay: foo(\n -x)
1281 Okay: foo(x\n [])
1282 Okay: x = '''\n''' + ''
1283 Okay: foo(x,\n -y)
1284 Okay: foo(x, # comment\n -y)
1285 """
1286 for context in _break_around_binary_operators(tokens):
1287 (token_type, text, previous_token_type, previous_text,
1288 line_break, unary_context, start) = context
1289 if (_is_binary_operator(token_type, text) and line_break and
1290 not unary_context and
1291 not _is_binary_operator(previous_token_type,
1292 previous_text)):
1293 yield start, "W503 line break before binary operator"
1294
1295
1296 @register_check
1297 def break_after_binary_operator(logical_line, tokens):
1298 r"""
1299 Avoid breaks after binary operators.
1300
1301 The preferred place to break around a binary operator is before the
1302 operator, not after it.
1303
1304 W504: (width == 0 +\n height == 0)
1305 W504: (width == 0 and\n height == 0)
1306 W504: var = (1 &\n ~2)
1307
1308 Okay: foo(\n -x)
1309 Okay: foo(x\n [])
1310 Okay: x = '''\n''' + ''
1311 Okay: x = '' + '''\n'''
1312 Okay: foo(x,\n -y)
1313 Okay: foo(x, # comment\n -y)
1314
1315 The following should be W504 but unary_context is tricky with these
1316 Okay: var = (1 /\n -2)
1317 Okay: var = (1 +\n -1 +\n -2)
1318 """
1319 prev_start = None
1320 for context in _break_around_binary_operators(tokens):
1321 (token_type, text, previous_token_type, previous_text,
1322 line_break, unary_context, start) = context
1323 if (_is_binary_operator(previous_token_type, previous_text) and
1324 line_break and
1325 not unary_context and
1326 not _is_binary_operator(token_type, text)):
1327 yield prev_start, "W504 line break after binary operator"
1328 prev_start = start
1329
1330
1331 @register_check
1332 def comparison_to_singleton(logical_line, noqa):
1333 r"""Comparison to singletons should use "is" or "is not".
1334
1335 Comparisons to singletons like None should always be done
1336 with "is" or "is not", never the equality operators.
1337
1338 Okay: if arg is not None:
1339 E711: if arg != None:
1340 E711: if None == arg:
1341 E712: if arg == True:
1342 E712: if False == arg:
1343
1344 Also, beware of writing if x when you really mean if x is not None
1345 -- e.g. when testing whether a variable or argument that defaults to
1346 None was set to some other value. The other value might have a type
1347 (such as a container) that could be false in a boolean context!
1348 """
1349 match = not noqa and COMPARE_SINGLETON_REGEX.search(logical_line)
1350 if match:
1351 singleton = match.group(1) or match.group(3)
1352 same = (match.group(2) == '==')
1353
1354 msg = "'if cond is %s:'" % (('' if same else 'not ') + singleton)
1355 if singleton in ('None',):
1356 code = 'E711'
1357 else:
1358 code = 'E712'
1359 nonzero = ((singleton == 'True' and same) or
1360 (singleton == 'False' and not same))
1361 msg += " or 'if %scond:'" % ('' if nonzero else 'not ')
1362 yield (match.start(2), ("%s comparison to %s should be %s" %
1363 (code, singleton, msg)), singleton, msg)
1364
1365
1366 @register_check
1367 def comparison_negative(logical_line):
1368 r"""Negative comparison should be done using "not in" and "is not".
1369
1370 Okay: if x not in y:\n pass
1371 Okay: assert (X in Y or X is Z)
1372 Okay: if not (X in Y):\n pass
1373 Okay: zz = x is not y
1374 E713: Z = not X in Y
1375 E713: if not X.B in Y:\n pass
1376 E714: if not X is Y:\n pass
1377 E714: Z = not X.B is Y
1378 """
1379 match = COMPARE_NEGATIVE_REGEX.search(logical_line)
1380 if match:
1381 pos = match.start(1)
1382 if match.group(2) == 'in':
1383 yield pos, "E713 test for membership should be 'not in'"
1384 else:
1385 yield pos, "E714 test for object identity should be 'is not'"
1386
1387
1388 @register_check
1389 def comparison_type(logical_line, noqa):
1390 r"""Object type comparisons should always use isinstance().
1391
1392 Do not compare types directly.
1393
1394 Okay: if isinstance(obj, int):
1395 E721: if type(obj) is type(1):
1396
1397 When checking if an object is a string, keep in mind that it might
1398 be a unicode string too! In Python 2.3, str and unicode have a
1399 common base class, basestring, so you can do:
1400
1401 Okay: if isinstance(obj, basestring):
1402 Okay: if type(a1) is type(b1):
1403 """
1404 match = COMPARE_TYPE_REGEX.search(logical_line)
1405 if match and not noqa:
1406 inst = match.group(1)
1407 if inst and isidentifier(inst) and inst not in SINGLETONS:
1408 return # Allow comparison for types which are not obvious
1409 yield match.start(), "E721 do not compare types, use 'isinstance()'"
1410
1411
1412 @register_check
1413 def bare_except(logical_line, noqa):
1414 r"""When catching exceptions, mention specific exceptions when
1415 possible.
1416
1417 Okay: except Exception:
1418 Okay: except BaseException:
1419 E722: except:
1420 """
1421 if noqa:
1422 return
1423
1424 regex = re.compile(r"except\s*:")
1425 match = regex.match(logical_line)
1426 if match:
1427 yield match.start(), "E722 do not use bare 'except'"
1428
1429
1430 @register_check
1431 def ambiguous_identifier(logical_line, tokens):
1432 r"""Never use the characters 'l', 'O', or 'I' as variable names.
1433
1434 In some fonts, these characters are indistinguishable from the
1435 numerals one and zero. When tempted to use 'l', use 'L' instead.
1436
1437 Okay: L = 0
1438 Okay: o = 123
1439 Okay: i = 42
1440 E741: l = 0
1441 E741: O = 123
1442 E741: I = 42
1443
1444 Variables can be bound in several other contexts, including class
1445 and function definitions, 'global' and 'nonlocal' statements,
1446 exception handlers, and 'with' statements.
1447
1448 Okay: except AttributeError as o:
1449 Okay: with lock as L:
1450 E741: except AttributeError as O:
1451 E741: with lock as l:
1452 E741: global I
1453 E741: nonlocal l
1454 E742: class I(object):
1455 E743: def l(x):
1456 """
1457 idents_to_avoid = ('l', 'O', 'I')
1458 prev_type, prev_text, prev_start, prev_end, __ = tokens[0]
1459 for token_type, text, start, end, line in tokens[1:]:
1460 ident = pos = None
1461 # identifiers on the lhs of an assignment operator
1462 if token_type == tokenize.OP and '=' in text:
1463 if prev_text in idents_to_avoid:
1464 ident = prev_text
1465 pos = prev_start
1466 # identifiers bound to values with 'as', 'global', or 'nonlocal'
1467 if prev_text in ('as', 'global', 'nonlocal'):
1468 if text in idents_to_avoid:
1469 ident = text
1470 pos = start
1471 if prev_text == 'class':
1472 if text in idents_to_avoid:
1473 yield start, "E742 ambiguous class definition '%s'", text
1474 if prev_text == 'def':
1475 if text in idents_to_avoid:
1476 yield start, "E743 ambiguous function definition '%s'", text
1477 if ident:
1478 yield pos, "E741 ambiguous variable name '%s'", ident
1479 prev_text = text
1480 prev_start = start
1481
1482
1483 @register_check
1484 def python_3000_has_key(logical_line, noqa):
1485 r"""The {}.has_key() method is removed in Python 3: use the 'in'
1486 operator.
1487
1488 Okay: if "alph" in d:\n print d["alph"]
1489 W601: assert d.has_key('alph')
1490 """
1491 pos = logical_line.find('.has_key(')
1492 if pos > -1 and not noqa:
1493 yield pos, "W601 .has_key() is deprecated, use 'in'"
1494
1495
1496 @register_check
1497 def python_3000_raise_comma(logical_line):
1498 r"""When raising an exception, use "raise ValueError('message')".
1499
1500 The older form is removed in Python 3.
1501
1502 Okay: raise DummyError("Message")
1503 W602: raise DummyError, "Message"
1504 """
1505 match = RAISE_COMMA_REGEX.match(logical_line)
1506 if match and not RERAISE_COMMA_REGEX.match(logical_line):
1507 yield match.end() - 1, "W602 deprecated form of raising exception"
1508
1509
1510 @register_check
1511 def python_3000_not_equal(logical_line):
1512 r"""New code should always use != instead of <>.
1513
1514 The older syntax is removed in Python 3.
1515
1516 Okay: if a != 'no':
1517 W603: if a <> 'no':
1518 """
1519 pos = logical_line.find('<>')
1520 if pos > -1:
1521 yield pos, "W603 '<>' is deprecated, use '!='"
1522
1523
1524 @register_check
1525 def python_3000_backticks(logical_line):
1526 r"""Use repr() instead of backticks in Python 3.
1527
1528 Okay: val = repr(1 + 2)
1529 W604: val = `1 + 2`
1530 """
1531 pos = logical_line.find('`')
1532 if pos > -1:
1533 yield pos, "W604 backticks are deprecated, use 'repr()'"
1534
1535
1536 @register_check
1537 def python_3000_invalid_escape_sequence(logical_line, tokens, noqa):
1538 r"""Invalid escape sequences are deprecated in Python 3.6.
1539
1540 Okay: regex = r'\.png$'
1541 W605: regex = '\.png$'
1542 """
1543 if noqa:
1544 return
1545
1546 # https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals
1547 valid = [
1548 '\n',
1549 '\\',
1550 '\'',
1551 '"',
1552 'a',
1553 'b',
1554 'f',
1555 'n',
1556 'r',
1557 't',
1558 'v',
1559 '0', '1', '2', '3', '4', '5', '6', '7',
1560 'x',
1561
1562 # Escape sequences only recognized in string literals
1563 'N',
1564 'u',
1565 'U',
1566 ]
1567
1568 for token_type, text, start, end, line in tokens:
1569 if token_type == tokenize.STRING:
1570 start_line, start_col = start
1571 quote = text[-3:] if text[-3:] in ('"""', "'''") else text[-1]
1572 # Extract string modifiers (e.g. u or r)
1573 quote_pos = text.index(quote)
1574 prefix = text[:quote_pos].lower()
1575 start = quote_pos + len(quote)
1576 string = text[start:-len(quote)]
1577
1578 if 'r' not in prefix:
1579 pos = string.find('\\')
1580 while pos >= 0:
1581 pos += 1
1582 if string[pos] not in valid:
1583 line = start_line + string.count('\n', 0, pos)
1584 if line == start_line:
1585 col = start_col + len(prefix) + len(quote) + pos
1586 else:
1587 col = pos - string.rfind('\n', 0, pos) - 1
1588 yield (
1589 (line, col - 1),
1590 "W605 invalid escape sequence '\\%s'",
1591 string[pos],
1592 )
1593 pos = string.find('\\', pos + 1)
1594
1595
1596 @register_check
1597 def python_3000_async_await_keywords(logical_line, tokens):
1598 """'async' and 'await' are reserved keywords starting at Python 3.7.
1599
1600 W606: async = 42
1601 W606: await = 42
1602 Okay: async def read(db):\n data = await db.fetch('SELECT ...')
1603 """
1604 # The Python tokenize library before Python 3.5 recognizes
1605 # async/await as a NAME token. Therefore, use a state machine to
1606 # look for the possible async/await constructs as defined by the
1607 # Python grammar:
1608 # https://docs.python.org/3/reference/grammar.html
1609
1610 state = None
1611 for token_type, text, start, end, line in tokens:
1612 error = False
1613
1614 if token_type == tokenize.NL:
1615 continue
1616
1617 if state is None:
1618 if token_type == tokenize.NAME:
1619 if text == 'async':
1620 state = ('async_stmt', start)
1621 elif text == 'await':
1622 state = ('await', start)
1623 elif (token_type == tokenize.NAME and
1624 text in ('def', 'for')):
1625 state = ('define', start)
1626
1627 elif state[0] == 'async_stmt':
1628 if token_type == tokenize.NAME and text in ('def', 'with', 'for'):
1629 # One of funcdef, with_stmt, or for_stmt. Return to
1630 # looking for async/await names.
1631 state = None
1632 else:
1633 error = True
1634 elif state[0] == 'await':
1635 if token_type == tokenize.NAME:
1636 # An await expression. Return to looking for async/await
1637 # names.
1638 state = None
1639 elif token_type == tokenize.OP and text == '(':
1640 state = None
1641 else:
1642 error = True
1643 elif state[0] == 'define':
1644 if token_type == tokenize.NAME and text in ('async', 'await'):
1645 error = True
1646 else:
1647 state = None
1648
1649 if error:
1650 yield (
1651 state[1],
1652 "W606 'async' and 'await' are reserved keywords starting with "
1653 "Python 3.7",
1654 )
1655 state = None
1656
1657 # Last token
1658 if state is not None:
1659 yield (
1660 state[1],
1661 "W606 'async' and 'await' are reserved keywords starting with "
1662 "Python 3.7",
1663 )
1664
1665
1666 ########################################################################
1667 @register_check
1668 def maximum_doc_length(logical_line, max_doc_length, noqa, tokens):
1669 r"""Limit all doc lines to a maximum of 72 characters.
1670
1671 For flowing long blocks of text (docstrings or comments), limiting
1672 the length to 72 characters is recommended.
1673
1674 Reports warning W505
1675 """
1676 if max_doc_length is None or noqa:
1677 return
1678
1679 prev_token = None
1680 skip_lines = set()
1681 # Skip lines that
1682 for token_type, text, start, end, line in tokens:
1683 if token_type not in SKIP_COMMENTS.union([tokenize.STRING]):
1684 skip_lines.add(line)
1685
1686 for token_type, text, start, end, line in tokens:
1687 # Skip lines that aren't pure strings
1688 if token_type == tokenize.STRING and skip_lines:
1689 continue
1690 if token_type in (tokenize.STRING, tokenize.COMMENT):
1691 # Only check comment-only lines
1692 if prev_token is None or prev_token in SKIP_TOKENS:
1693 lines = line.splitlines()
1694 for line_num, physical_line in enumerate(lines):
1695 if hasattr(physical_line, 'decode'): # Python 2
1696 # The line could contain multi-byte characters
1697 try:
1698 physical_line = physical_line.decode('utf-8')
1699 except UnicodeError:
1700 pass
1701 if start[0] + line_num == 1 and line.startswith('#!'):
1702 return
1703 length = len(physical_line)
1704 chunks = physical_line.split()
1705 if token_type == tokenize.COMMENT:
1706 if (len(chunks) == 2 and
1707 length - len(chunks[-1]) < MAX_DOC_LENGTH):
1708 continue
1709 if len(chunks) == 1 and line_num + 1 < len(lines):
1710 if (len(chunks) == 1 and
1711 length - len(chunks[-1]) < MAX_DOC_LENGTH):
1712 continue
1713 if length > max_doc_length:
1714 doc_error = (start[0] + line_num, max_doc_length)
1715 yield (doc_error, "W505 doc line too long "
1716 "(%d > %d characters)",
1717 length, max_doc_length)
1718 prev_token = token_type
1719
1720
1721 ########################################################################
1722 # Helper functions
1723 ########################################################################
1724
1725
1726 if sys.version_info < (3,):
1727 # Python 2: implicit encoding.
1728 def readlines(filename):
1729 """Read the source code."""
1730 with open(filename, 'rU') as f:
1731 return f.readlines()
1732 isidentifier = re.compile(r'[a-zA-Z_]\w*$').match
1733 stdin_get_value = sys.stdin.read
1734 else:
1735 # Python 3
1736 def readlines(filename):
1737 """Read the source code."""
1738 try:
1739 with open(filename, 'rb') as f:
1740 (coding, lines) = tokenize.detect_encoding(f.readline)
1741 f = TextIOWrapper(f, coding, line_buffering=True)
1742 return [line.decode(coding) for line in lines] + f.readlines()
1743 except (LookupError, SyntaxError, UnicodeError):
1744 # Fall back if file encoding is improperly declared
1745 with open(filename, encoding='latin-1') as f:
1746 return f.readlines()
1747 isidentifier = str.isidentifier
1748
1749 def stdin_get_value():
1750 """Read the value from stdin."""
1751 return TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
1752
1753 noqa = lru_cache(512)(re.compile(r'# no(?:qa|pep8)\b', re.I).search)
1754
1755
1756 def expand_indent(line):
1757 r"""Return the amount of indentation.
1758
1759 Tabs are expanded to the next multiple of 8.
1760
1761 >>> expand_indent(' ')
1762 4
1763 >>> expand_indent('\t')
1764 8
1765 >>> expand_indent(' \t')
1766 8
1767 >>> expand_indent(' \t')
1768 16
1769 """
1770 if '\t' not in line:
1771 return len(line) - len(line.lstrip())
1772 result = 0
1773 for char in line:
1774 if char == '\t':
1775 result = result // 8 * 8 + 8
1776 elif char == ' ':
1777 result += 1
1778 else:
1779 break
1780 return result
1781
1782
1783 def mute_string(text):
1784 """Replace contents with 'xxx' to prevent syntax matching.
1785
1786 >>> mute_string('"abc"')
1787 '"xxx"'
1788 >>> mute_string("'''abc'''")
1789 "'''xxx'''"
1790 >>> mute_string("r'abc'")
1791 "r'xxx'"
1792 """
1793 # String modifiers (e.g. u or r)
1794 start = text.index(text[-1]) + 1
1795 end = len(text) - 1
1796 # Triple quotes
1797 if text[-3:] in ('"""', "'''"):
1798 start += 2
1799 end -= 2
1800 return text[:start] + 'x' * (end - start) + text[end:]
1801
1802
1803 def parse_udiff(diff, patterns=None, parent='.'):
1804 """Return a dictionary of matching lines."""
1805 # For each file of the diff, the entry key is the filename,
1806 # and the value is a set of row numbers to consider.
1807 rv = {}
1808 path = nrows = None
1809 for line in diff.splitlines():
1810 if nrows:
1811 if line[:1] != '-':
1812 nrows -= 1
1813 continue
1814 if line[:3] == '@@ ':
1815 hunk_match = HUNK_REGEX.match(line)
1816 (row, nrows) = [int(g or '1') for g in hunk_match.groups()]
1817 rv[path].update(range(row, row + nrows))
1818 elif line[:3] == '+++':
1819 path = line[4:].split('\t', 1)[0]
1820 # Git diff will use (i)ndex, (w)ork tree, (c)ommit and
1821 # (o)bject instead of a/b/c/d as prefixes for patches
1822 if path[:2] in ('b/', 'w/', 'i/'):
1823 path = path[2:]
1824 rv[path] = set()
1825 return {
1826 os.path.join(parent, filepath): rows
1827 for (filepath, rows) in rv.items()
1828 if rows and filename_match(filepath, patterns)
1829 }
1830
1831
1832 def normalize_paths(value, parent=os.curdir):
1833 """Parse a comma-separated list of paths.
1834
1835 Return a list of absolute paths.
1836 """
1837 if not value:
1838 return []
1839 if isinstance(value, list):
1840 return value
1841 paths = []
1842 for path in value.split(','):
1843 path = path.strip()
1844 if '/' in path:
1845 path = os.path.abspath(os.path.join(parent, path))
1846 paths.append(path.rstrip('/'))
1847 return paths
1848
1849
1850 def filename_match(filename, patterns, default=True):
1851 """Check if patterns contains a pattern that matches filename.
1852
1853 If patterns is unspecified, this always returns True.
1854 """
1855 if not patterns:
1856 return default
1857 return any(fnmatch(filename, pattern) for pattern in patterns)
1858
1859
1860 def update_counts(s, counts):
1861 r"""Adds one to the counts of each appearance of characters in s,
1862 for characters in counts"""
1863 for char in s:
1864 if char in counts:
1865 counts[char] += 1
1866
1867
1868 def _is_eol_token(token):
1869 return token[0] in NEWLINE or token[4][token[3][1]:].lstrip() == '\\\n'
1870
1871
1872 ########################################################################
1873 # Framework to run all checks
1874 ########################################################################
1875
1876
1877 class Checker(object):
1878 """Load a Python source file, tokenize it, check coding style."""
1879
1880 def __init__(self, filename=None, lines=None,
1881 options=None, report=None, **kwargs):
1882 if options is None:
1883 options = StyleGuide(kwargs).options
1884 else:
1885 assert not kwargs
1886 self._io_error = None
1887 self._physical_checks = options.physical_checks
1888 self._logical_checks = options.logical_checks
1889 self._ast_checks = options.ast_checks
1890 self.max_line_length = options.max_line_length
1891 self.max_doc_length = options.max_doc_length
1892 self.multiline = False # in a multiline string?
1893 self.hang_closing = options.hang_closing
1894 self.verbose = options.verbose
1895 self.filename = filename
1896 # Dictionary where a checker can store its custom state.
1897 self._checker_states = {}
1898 if filename is None:
1899 self.filename = 'stdin'
1900 self.lines = lines or []
1901 elif filename == '-':
1902 self.filename = 'stdin'
1903 self.lines = stdin_get_value().splitlines(True)
1904 elif lines is None:
1905 try:
1906 self.lines = readlines(filename)
1907 except IOError:
1908 (exc_type, exc) = sys.exc_info()[:2]
1909 self._io_error = '%s: %s' % (exc_type.__name__, exc)
1910 self.lines = []
1911 else:
1912 self.lines = lines
1913 if self.lines:
1914 ord0 = ord(self.lines[0][0])
1915 if ord0 in (0xef, 0xfeff): # Strip the UTF-8 BOM
1916 if ord0 == 0xfeff:
1917 self.lines[0] = self.lines[0][1:]
1918 elif self.lines[0][:3] == '\xef\xbb\xbf':
1919 self.lines[0] = self.lines[0][3:]
1920 self.report = report or options.report
1921 self.report_error = self.report.error
1922 self.report_error_args = self.report.error_args
1923 self.noqa = False
1924
1925 # added for eric6 integration
1926 self.options = options
1927
1928 def report_invalid_syntax(self):
1929 """Check if the syntax is valid."""
1930 (exc_type, exc) = sys.exc_info()[:2]
1931 if len(exc.args) > 1:
1932 offset = exc.args[1]
1933 if len(offset) > 2:
1934 offset = offset[1:3]
1935 else:
1936 offset = (1, 0)
1937 self.report_error_args(offset[0], offset[1] or 0,
1938 'E901', self.report_invalid_syntax,
1939 exc_type.__name__, exc.args[0])
1940
1941 def readline(self):
1942 """Get the next line from the input buffer."""
1943 if self.line_number >= self.total_lines:
1944 return ''
1945 line = self.lines[self.line_number]
1946 self.line_number += 1
1947 if self.indent_char is None and line[:1] in WHITESPACE:
1948 self.indent_char = line[0]
1949 return line
1950
1951 def run_check(self, check, argument_names):
1952 """Run a check plugin."""
1953 arguments = []
1954 for name in argument_names:
1955 arguments.append(getattr(self, name))
1956 return check(*arguments)
1957
1958 def init_checker_state(self, name, argument_names):
1959 """Prepare custom state for the specific checker plugin."""
1960 if 'checker_state' in argument_names:
1961 self.checker_state = self._checker_states.setdefault(name, {})
1962
1963 def check_physical(self, line):
1964 """Run all physical checks on a raw input line."""
1965 self.physical_line = line
1966 for name, check, argument_names in self._physical_checks:
1967 self.init_checker_state(name, argument_names)
1968 result = self.run_check(check, argument_names)
1969 if result is not None:
1970 (offset, text) = result[:2]
1971 args = result[2:]
1972 self.report_error_args(
1973 self.line_number, offset, text, check, *args)
1974 if text[:4] == 'E101':
1975 self.indent_char = line[0]
1976
1977 def build_tokens_line(self):
1978 """Build a logical line from tokens."""
1979 logical = []
1980 comments = []
1981 length = 0
1982 prev_row = prev_col = mapping = None
1983 for token_type, text, start, end, line in self.tokens:
1984 if token_type in SKIP_TOKENS:
1985 continue
1986 if not mapping:
1987 mapping = [(0, start)]
1988 if token_type == tokenize.COMMENT:
1989 comments.append(text)
1990 continue
1991 if token_type == tokenize.STRING:
1992 text = mute_string(text)
1993 if prev_row:
1994 (start_row, start_col) = start
1995 if prev_row != start_row: # different row
1996 prev_text = self.lines[prev_row - 1][prev_col - 1]
1997 if prev_text == ',' or (prev_text not in '{[(' and
1998 text not in '}])'):
1999 text = ' ' + text
2000 elif prev_col != start_col: # different column
2001 text = line[prev_col:start_col] + text
2002 logical.append(text)
2003 length += len(text)
2004 mapping.append((length, end))
2005 (prev_row, prev_col) = end
2006 self.logical_line = ''.join(logical)
2007 self.noqa = comments and noqa(''.join(comments))
2008 return mapping
2009
2010 def check_logical(self):
2011 """Build a line from tokens and run all logical checks on it."""
2012 self.report.increment_logical_line()
2013 mapping = self.build_tokens_line()
2014 if not mapping:
2015 return
2016
2017 mapping_offsets = [offset for offset, _ in mapping]
2018 (start_row, start_col) = mapping[0][1]
2019 start_line = self.lines[start_row - 1]
2020 self.indent_level = expand_indent(start_line[:start_col])
2021 if self.blank_before < self.blank_lines:
2022 self.blank_before = self.blank_lines
2023 if self.verbose >= 2:
2024 print(self.logical_line[:80].rstrip())
2025 for name, check, argument_names in self._logical_checks:
2026 if self.verbose >= 4:
2027 print(' ' + name)
2028 self.init_checker_state(name, argument_names)
2029 for result in self.run_check(check, argument_names) or ():
2030 offset, text = result[:2]
2031 args = result[2:]
2032 if not isinstance(offset, tuple):
2033 # As mappings are ordered, bisecting is a fast way
2034 # to find a given offset in them.
2035 token_offset, pos = mapping[bisect.bisect_left(
2036 mapping_offsets, offset)]
2037 offset = (pos[0], pos[1] + offset - token_offset)
2038 self.report_error_args(
2039 offset[0], offset[1], text, check, *args)
2040 if self.logical_line:
2041 self.previous_indent_level = self.indent_level
2042 self.previous_logical = self.logical_line
2043 if not self.indent_level:
2044 self.previous_unindented_logical_line = self.logical_line
2045 self.blank_lines = 0
2046 self.tokens = []
2047
2048 def check_ast(self):
2049 """Build the file's AST and run all AST checks."""
2050 try:
2051 tree = compile(''.join(self.lines), '', 'exec', PyCF_ONLY_AST)
2052 except (ValueError, SyntaxError, TypeError):
2053 return self.report_invalid_syntax()
2054 for name, cls, __ in self._ast_checks:
2055 # extended API for eric6 integration
2056 checker = cls(tree, self.filename, self.options)
2057 for args in checker.run():
2058 lineno = args[0]
2059 if not self.lines or not noqa(self.lines[lineno - 1]):
2060 self.report_error_args(lineno, *args[1:])
2061
2062 def generate_tokens(self):
2063 """Tokenize file, run physical line checks and yield tokens."""
2064 if self._io_error:
2065 self.report_error_args(1, 0, 'E902', self._io_error, readlines)
2066 tokengen = tokenize.generate_tokens(self.readline)
2067 try:
2068 for token in tokengen:
2069 if token[2][0] > self.total_lines:
2070 return
2071 self.noqa = token[4] and noqa(token[4])
2072 self.maybe_check_physical(token)
2073 yield token
2074 except (SyntaxError, tokenize.TokenError):
2075 self.report_invalid_syntax()
2076
2077 def maybe_check_physical(self, token):
2078 """If appropriate for token, check current physical line(s)."""
2079 # Called after every token, but act only on end of line.
2080 if _is_eol_token(token):
2081 # Obviously, a newline token ends a single physical line.
2082 self.check_physical(token[4])
2083 elif token[0] == tokenize.STRING and '\n' in token[1]:
2084 # Less obviously, a string that contains newlines is a
2085 # multiline string, either triple-quoted or with internal
2086 # newlines backslash-escaped. Check every physical line in
2087 # the string *except* for the last one: its newline is
2088 # outside of the multiline string, so we consider it a
2089 # regular physical line, and will check it like any other
2090 # physical line.
2091 #
2092 # Subtleties:
2093 # - we don't *completely* ignore the last line; if it
2094 # contains the magical "# noqa" comment, we disable all
2095 # physical checks for the entire multiline string
2096 # - have to wind self.line_number back because initially it
2097 # points to the last line of the string, and we want
2098 # check_physical() to give accurate feedback
2099 if noqa(token[4]):
2100 return
2101 self.multiline = True
2102 self.line_number = token[2][0]
2103 _, src, (_, offset), _, _ = token
2104 src = self.lines[self.line_number - 1][:offset] + src
2105 for line in src.split('\n')[:-1]:
2106 self.check_physical(line + '\n')
2107 self.line_number += 1
2108 self.multiline = False
2109
2110 def check_all(self, expected=None, line_offset=0):
2111 """Run all checks on the input file."""
2112 self.report.init_file(self.filename, self.lines, expected, line_offset)
2113 self.total_lines = len(self.lines)
2114 if self._ast_checks:
2115 self.check_ast()
2116 self.line_number = 0
2117 self.indent_char = None
2118 self.indent_level = self.previous_indent_level = 0
2119 self.previous_logical = ''
2120 self.previous_unindented_logical_line = ''
2121 self.tokens = []
2122 self.blank_lines = self.blank_before = 0
2123 parens = 0
2124 for token in self.generate_tokens():
2125 self.tokens.append(token)
2126 token_type, text = token[0:2]
2127 if self.verbose >= 3:
2128 if token[2][0] == token[3][0]:
2129 pos = '[%s:%s]' % (token[2][1] or '', token[3][1])
2130 else:
2131 pos = 'l.%s' % token[3][0]
2132 print('l.%s\t%s\t%s\t%r' %
2133 (token[2][0], pos, tokenize.tok_name[token[0]], text))
2134 if token_type == tokenize.OP:
2135 if text in '([{':
2136 parens += 1
2137 elif text in '}])':
2138 parens -= 1
2139 elif not parens:
2140 if token_type in NEWLINE:
2141 if token_type == tokenize.NEWLINE:
2142 self.check_logical()
2143 self.blank_before = 0
2144 elif len(self.tokens) == 1:
2145 # The physical line contains only this token.
2146 self.blank_lines += 1
2147 del self.tokens[0]
2148 else:
2149 self.check_logical()
2150 if self.tokens:
2151 self.check_physical(self.lines[-1])
2152 self.check_logical()
2153 return self.report.get_file_results()
2154
2155
2156 class BaseReport(object):
2157 """Collect the results of the checks."""
2158
2159 print_filename = False
2160
2161 def __init__(self, options):
2162 self._benchmark_keys = options.benchmark_keys
2163 self._ignore_code = options.ignore_code
2164 # Results
2165 self.elapsed = 0
2166 self.total_errors = 0
2167 self.counters = dict.fromkeys(self._benchmark_keys, 0)
2168 self.messages = {}
2169
2170 def start(self):
2171 """Start the timer."""
2172 self._start_time = time.time()
2173
2174 def stop(self):
2175 """Stop the timer."""
2176 self.elapsed = time.time() - self._start_time
2177
2178 def init_file(self, filename, lines, expected, line_offset):
2179 """Signal a new file."""
2180 self.filename = filename
2181 self.lines = lines
2182 self.expected = expected or ()
2183 self.line_offset = line_offset
2184 self.file_errors = 0
2185 self.counters['files'] += 1
2186 self.counters['physical lines'] += len(lines)
2187
2188 def increment_logical_line(self):
2189 """Signal a new logical line."""
2190 self.counters['logical lines'] += 1
2191
2192 def error(self, line_number, offset, text, check):
2193 """Report an error, according to options."""
2194 code = text[:4]
2195 if self._ignore_code(code):
2196 return
2197 if code in self.counters:
2198 self.counters[code] += 1
2199 else:
2200 self.counters[code] = 1
2201 self.messages[code] = []
2202 # Don't care about expected errors or warnings
2203 if code in self.expected:
2204 return
2205 if self.print_filename and not self.file_errors:
2206 print(self.filename)
2207 self.file_errors += 1
2208 self.total_errors += 1
2209 return code
2210
2211 def error_args(self, line_number, offset, text, check, *args):
2212 """Report an error, according to options."""
2213 code = text[:4]
2214 if self._ignore_code(code):
2215 return
2216 if code in self.counters:
2217 self.counters[code] += 1
2218 else:
2219 self.counters[code] = 1
2220 self.messages[code] = args
2221 # Don't care about expected errors or warnings
2222 if code in self.expected:
2223 return
2224 if self.print_filename and not self.file_errors:
2225 print(self.filename)
2226 self.file_errors += 1
2227 self.total_errors += 1
2228 return code
2229
2230 def get_file_results(self):
2231 """Return the count of errors and warnings for this file."""
2232 return self.file_errors
2233
2234 def get_count(self, prefix=''):
2235 """Return the total count of errors and warnings."""
2236 return sum(self.counters[key]
2237 for key in self.messages if key.startswith(prefix))
2238
2239 def get_statistics(self, prefix=''):
2240 """Get statistics for message codes that start with the prefix.
2241
2242 prefix='' matches all errors and warnings
2243 prefix='E' matches all errors
2244 prefix='W' matches all warnings
2245 prefix='E4' matches all errors that have to do with imports
2246 """
2247 return ['%-7s %s %s' % (self.counters[key], key, self.messages[key])
2248 for key in sorted(self.messages) if key.startswith(prefix)]
2249
2250 def print_statistics(self, prefix=''):
2251 """Print overall statistics (number of errors and warnings)."""
2252 for line in self.get_statistics(prefix):
2253 print(line)
2254
2255 def print_benchmark(self):
2256 """Print benchmark numbers."""
2257 print('%-7.2f %s' % (self.elapsed, 'seconds elapsed'))
2258 if self.elapsed:
2259 for key in self._benchmark_keys:
2260 print('%-7d %s per second (%d total)' %
2261 (self.counters[key] / self.elapsed, key,
2262 self.counters[key]))
2263
2264
2265 class FileReport(BaseReport):
2266 """Collect the results of the checks and print the filenames."""
2267
2268 print_filename = True
2269
2270
2271 class StandardReport(BaseReport):
2272 """Collect and print the results of the checks."""
2273
2274 def __init__(self, options):
2275 super(StandardReport, self).__init__(options)
2276 self._fmt = REPORT_FORMAT.get(options.format.lower(),
2277 options.format)
2278 self._repeat = options.repeat
2279 self._show_source = options.show_source
2280 self._show_pep8 = options.show_pep8
2281
2282 def init_file(self, filename, lines, expected, line_offset):
2283 """Signal a new file."""
2284 self._deferred_print = []
2285 return super(StandardReport, self).init_file(
2286 filename, lines, expected, line_offset)
2287
2288 def error(self, line_number, offset, text, check):
2289 """Report an error, according to options."""
2290 code = super(StandardReport, self).error(line_number, offset,
2291 text, check)
2292 if code and (self.counters[code] == 1 or self._repeat):
2293 self._deferred_print.append(
2294 (line_number, offset, code, text[5:], check.__doc__))
2295 return code
2296
2297 def error_args(self, line_number, offset, code, check, *args):
2298 """Report an error, according to options."""
2299 code = super(StandardReport, self).error_args(line_number, offset,
2300 code, check, *args)
2301 if code and (self.counters[code] == 1 or self._repeat):
2302 self._deferred_print.append(
2303 (line_number, offset, code, args, check.__doc__))
2304 return code
2305
2306 def get_file_results(self):
2307 """Print results and return the overall count for this file."""
2308 self._deferred_print.sort()
2309 for line_number, offset, code, text, doc in self._deferred_print:
2310 print(self._fmt % {
2311 'path': self.filename,
2312 'row': self.line_offset + line_number, 'col': offset + 1,
2313 'code': code, 'text': text,
2314 })
2315 if self._show_source:
2316 if line_number > len(self.lines):
2317 line = ''
2318 else:
2319 line = self.lines[line_number - 1]
2320 print(line.rstrip())
2321 print(re.sub(r'\S', ' ', line[:offset]) + '^')
2322 if self._show_pep8 and doc:
2323 print(' ' + doc.strip())
2324
2325 # stdout is block buffered when not stdout.isatty().
2326 # line can be broken where buffer boundary since other
2327 # processes write to same file.
2328 # flush() after print() to avoid buffer boundary.
2329 # Typical buffer size is 8192. line written safely when
2330 # len(line) < 8192.
2331 sys.stdout.flush()
2332 return self.file_errors
2333
2334
2335 class DiffReport(StandardReport):
2336 """Collect and print the results for the changed lines only."""
2337
2338 def __init__(self, options):
2339 super(DiffReport, self).__init__(options)
2340 self._selected = options.selected_lines
2341
2342 def error(self, line_number, offset, text, check):
2343 if line_number not in self._selected[self.filename]:
2344 return
2345 return super(DiffReport, self).error(line_number, offset, text, check)
2346
2347
2348 class StyleGuide(object):
2349 """Initialize a PEP-8 instance with few options."""
2350
2351 def __init__(self, *args, **kwargs):
2352 # build options from the command line
2353 self.checker_class = kwargs.pop('checker_class', Checker)
2354 parse_argv = kwargs.pop('parse_argv', False)
2355 config_file = kwargs.pop('config_file', False)
2356 parser = kwargs.pop('parser', None)
2357 # build options from dict
2358 options_dict = dict(*args, **kwargs)
2359 arglist = None if parse_argv else options_dict.get('paths', None)
2360 verbose = options_dict.get('verbose', None)
2361 options, self.paths = process_options(
2362 arglist, parse_argv, config_file, parser, verbose)
2363 if options_dict:
2364 options.__dict__.update(options_dict)
2365 if 'paths' in options_dict:
2366 self.paths = options_dict['paths']
2367
2368 self.runner = self.input_file
2369 self.options = options
2370
2371 if not options.reporter:
2372 options.reporter = BaseReport if options.quiet else StandardReport
2373
2374 options.select = tuple(options.select or ())
2375 # if not (options.select or options.ignore or
2376 # options.testsuite or options.doctest) and DEFAULT_IGNORE:
2377 # # The default choice: ignore controversial checks
2378 # options.ignore = tuple(DEFAULT_IGNORE.split(','))
2379 # else:
2380 # # Ignore all checks which are not explicitly selected or all if no
2381 # options.ignore = ('',) if options.select else tuple(options.ignore)
2382
2383 # check is ignored or explicitly selected
2384 options.ignore = ('',) if options.select else tuple(options.ignore)
2385 options.benchmark_keys = BENCHMARK_KEYS[:]
2386 options.ignore_code = self.ignore_code
2387 options.physical_checks = self.get_checks('physical_line')
2388 options.logical_checks = self.get_checks('logical_line')
2389 options.ast_checks = self.get_checks('tree')
2390 self.init_report()
2391
2392 def init_report(self, reporter=None):
2393 """Initialize the report instance."""
2394 self.options.report = (reporter or self.options.reporter)(self.options)
2395 return self.options.report
2396
2397 def check_files(self, paths=None):
2398 """Run all checks on the paths."""
2399 if paths is None:
2400 paths = self.paths
2401 report = self.options.report
2402 runner = self.runner
2403 report.start()
2404 try:
2405 for path in paths:
2406 if os.path.isdir(path):
2407 self.input_dir(path)
2408 elif not self.excluded(path):
2409 runner(path)
2410 except KeyboardInterrupt:
2411 print('... stopped')
2412 report.stop()
2413 return report
2414
2415 def input_file(self, filename, lines=None, expected=None, line_offset=0):
2416 """Run all checks on a Python source file."""
2417 if self.options.verbose:
2418 print('checking %s' % filename)
2419 fchecker = self.checker_class(
2420 filename, lines=lines, options=self.options)
2421 return fchecker.check_all(expected=expected, line_offset=line_offset)
2422
2423 def input_dir(self, dirname):
2424 """Check all files in this directory and all subdirectories."""
2425 dirname = dirname.rstrip('/')
2426 if self.excluded(dirname):
2427 return 0
2428 counters = self.options.report.counters
2429 verbose = self.options.verbose
2430 filepatterns = self.options.filename
2431 runner = self.runner
2432 for root, dirs, files in os.walk(dirname):
2433 if verbose:
2434 print('directory ' + root)
2435 counters['directories'] += 1
2436 for subdir in sorted(dirs):
2437 if self.excluded(subdir, root):
2438 dirs.remove(subdir)
2439 for filename in sorted(files):
2440 # contain a pattern that matches?
2441 if ((filename_match(filename, filepatterns) and
2442 not self.excluded(filename, root))):
2443 runner(os.path.join(root, filename))
2444
2445 def excluded(self, filename, parent=None):
2446 """Check if the file should be excluded.
2447
2448 Check if 'options.exclude' contains a pattern matching filename.
2449 """
2450 if not self.options.exclude:
2451 return False
2452 basename = os.path.basename(filename)
2453 if filename_match(basename, self.options.exclude):
2454 return True
2455 if parent:
2456 filename = os.path.join(parent, filename)
2457 filename = os.path.abspath(filename)
2458 return filename_match(filename, self.options.exclude)
2459
2460 def ignore_code(self, code):
2461 """Check if the error code should be ignored.
2462
2463 If 'options.select' contains a prefix of the error code,
2464 return False. Else, if 'options.ignore' contains a prefix of
2465 the error code, return True.
2466 """
2467 if len(code) < 4 and any(s.startswith(code)
2468 for s in self.options.select):
2469 return False
2470 return (code.startswith(self.options.ignore) and
2471 not code.startswith(self.options.select))
2472
2473 def get_checks(self, argument_name):
2474 """Get all the checks for this category.
2475
2476 Find all globally visible functions where the first argument
2477 name starts with argument_name and which contain selected tests.
2478 """
2479 checks = []
2480 for check, attrs in _checks[argument_name].items():
2481 (codes, args) = attrs
2482 if any(not (code and self.ignore_code(code)) for code in codes):
2483 checks.append((check.__name__, check, args))
2484 return sorted(checks)
2485
2486
2487 def get_parser(prog='pycodestyle', version=__version__):
2488 """Create the parser for the program."""
2489 parser = OptionParser(prog=prog, version=version,
2490 usage="%prog [options] input ...")
2491 parser.config_options = [
2492 'exclude', 'filename', 'select', 'ignore', 'max-line-length',
2493 'max-doc-length', 'hang-closing', 'count', 'format', 'quiet',
2494 'show-pep8', 'show-source', 'statistics', 'verbose']
2495 parser.add_option('-v', '--verbose', default=0, action='count',
2496 help="print status messages, or debug with -vv")
2497 parser.add_option('-q', '--quiet', default=0, action='count',
2498 help="report only file names, or nothing with -qq")
2499 parser.add_option('-r', '--repeat', default=True, action='store_true',
2500 help="(obsolete) show all occurrences of the same error")
2501 parser.add_option('--first', action='store_false', dest='repeat',
2502 help="show first occurrence of each error")
2503 parser.add_option('--exclude', metavar='patterns', default=DEFAULT_EXCLUDE,
2504 help="exclude files or directories which match these "
2505 "comma separated patterns (default: %default)")
2506 parser.add_option('--filename', metavar='patterns', default='*.py',
2507 help="when parsing directories, only check filenames "
2508 "matching these comma separated patterns "
2509 "(default: %default)")
2510 parser.add_option('--select', metavar='errors', default='',
2511 help="select errors and warnings (e.g. E,W6)")
2512 parser.add_option('--ignore', metavar='errors', default='',
2513 help="skip errors and warnings (e.g. E4,W) "
2514 "(default: %s)" % DEFAULT_IGNORE)
2515 parser.add_option('--show-source', action='store_true',
2516 help="show source code for each error")
2517 parser.add_option('--show-pep8', action='store_true',
2518 help="show text of PEP 8 for each error "
2519 "(implies --first)")
2520 parser.add_option('--statistics', action='store_true',
2521 help="count errors and warnings")
2522 parser.add_option('--count', action='store_true',
2523 help="print total number of errors and warnings "
2524 "to standard error and set exit code to 1 if "
2525 "total is not null")
2526 parser.add_option('--max-line-length', type='int', metavar='n',
2527 default=MAX_LINE_LENGTH,
2528 help="set maximum allowed line length "
2529 "(default: %default)")
2530 parser.add_option('--max-doc-length', type='int', metavar='n',
2531 default=None,
2532 help="set maximum allowed doc line length and perform "
2533 "these checks (unchecked if not set)")
2534 parser.add_option('--hang-closing', action='store_true',
2535 help="hang closing bracket instead of matching "
2536 "indentation of opening bracket's line")
2537 parser.add_option('--format', metavar='format', default='default',
2538 help="set the error format [default|pylint|<custom>]")
2539 parser.add_option('--diff', action='store_true',
2540 help="report changes only within line number ranges in "
2541 "the unified diff received on STDIN")
2542 group = parser.add_option_group("Testing Options")
2543 if os.path.exists(TESTSUITE_PATH):
2544 group.add_option('--testsuite', metavar='dir',
2545 help="run regression tests from dir")
2546 group.add_option('--doctest', action='store_true',
2547 help="run doctest on myself")
2548 group.add_option('--benchmark', action='store_true',
2549 help="measure processing speed")
2550 return parser
2551
2552
2553 def read_config(options, args, arglist, parser):
2554 """Read and parse configurations.
2555
2556 If a config file is specified on the command line with the
2557 "--config" option, then only it is used for configuration.
2558
2559 Otherwise, the user configuration (~/.config/pycodestyle) and any
2560 local configurations in the current directory or above will be
2561 merged together (in that order) using the read method of
2562 ConfigParser.
2563 """
2564 config = RawConfigParser()
2565
2566 cli_conf = options.config
2567
2568 local_dir = os.curdir
2569
2570 if USER_CONFIG and os.path.isfile(USER_CONFIG):
2571 if options.verbose:
2572 print('user configuration: %s' % USER_CONFIG)
2573 config.read(USER_CONFIG)
2574
2575 parent = tail = args and os.path.abspath(os.path.commonprefix(args))
2576 while tail:
2577 if config.read(os.path.join(parent, fn) for fn in PROJECT_CONFIG):
2578 local_dir = parent
2579 if options.verbose:
2580 print('local configuration: in %s' % parent)
2581 break
2582 (parent, tail) = os.path.split(parent)
2583
2584 if cli_conf and os.path.isfile(cli_conf):
2585 if options.verbose:
2586 print('cli configuration: %s' % cli_conf)
2587 config.read(cli_conf)
2588
2589 pycodestyle_section = None
2590 if config.has_section(parser.prog):
2591 pycodestyle_section = parser.prog
2592 elif config.has_section('pep8'):
2593 pycodestyle_section = 'pep8' # Deprecated
2594 warnings.warn('[pep8] section is deprecated. Use [pycodestyle].')
2595
2596 if pycodestyle_section:
2597 option_list = {o.dest: o.type or o.action for o in parser.option_list}
2598
2599 # First, read the default values
2600 (new_options, __) = parser.parse_args([])
2601
2602 # Second, parse the configuration
2603 for opt in config.options(pycodestyle_section):
2604 if opt.replace('_', '-') not in parser.config_options:
2605 print(" unknown option '%s' ignored" % opt)
2606 continue
2607 if options.verbose > 1:
2608 print(" %s = %s" % (opt,
2609 config.get(pycodestyle_section, opt)))
2610 normalized_opt = opt.replace('-', '_')
2611 opt_type = option_list[normalized_opt]
2612 if opt_type in ('int', 'count'):
2613 value = config.getint(pycodestyle_section, opt)
2614 elif opt_type in ('store_true', 'store_false'):
2615 value = config.getboolean(pycodestyle_section, opt)
2616 else:
2617 value = config.get(pycodestyle_section, opt)
2618 if normalized_opt == 'exclude':
2619 value = normalize_paths(value, local_dir)
2620 setattr(new_options, normalized_opt, value)
2621
2622 # Third, overwrite with the command-line options
2623 (options, __) = parser.parse_args(arglist, values=new_options)
2624 options.doctest = options.testsuite = False
2625 return options
2626
2627
2628 def process_options(arglist=None, parse_argv=False, config_file=None,
2629 parser=None, verbose=None):
2630 """Process options passed either via arglist or command line args.
2631
2632 Passing in the ``config_file`` parameter allows other tools, such as
2633 flake8 to specify their own options to be processed in pycodestyle.
2634 """
2635 if not parser:
2636 parser = get_parser()
2637 if not parser.has_option('--config'):
2638 group = parser.add_option_group("Configuration", description=(
2639 "The project options are read from the [%s] section of the "
2640 "tox.ini file or the setup.cfg file located in any parent folder "
2641 "of the path(s) being processed. Allowed options are: %s." %
2642 (parser.prog, ', '.join(parser.config_options))))
2643 group.add_option('--config', metavar='path', default=config_file,
2644 help="user config file location")
2645 # Don't read the command line if the module is used as a library.
2646 if not arglist and not parse_argv:
2647 arglist = []
2648 # If parse_argv is True and arglist is None, arguments are
2649 # parsed from the command line (sys.argv)
2650 (options, args) = parser.parse_args(arglist)
2651 options.reporter = None
2652
2653 # If explicitly specified verbosity, override any `-v` CLI flag
2654 if verbose is not None:
2655 options.verbose = verbose
2656
2657 if options.ensure_value('testsuite', False):
2658 args.append(options.testsuite)
2659 elif not options.ensure_value('doctest', False):
2660 if parse_argv and not args:
2661 if options.diff or any(os.path.exists(name)
2662 for name in PROJECT_CONFIG):
2663 args = ['.']
2664 else:
2665 parser.error('input not specified')
2666 options = read_config(options, args, arglist, parser)
2667 options.reporter = parse_argv and options.quiet == 1 and FileReport
2668
2669 options.filename = _parse_multi_options(options.filename)
2670 options.exclude = normalize_paths(options.exclude)
2671 options.select = _parse_multi_options(options.select)
2672 options.ignore = _parse_multi_options(options.ignore)
2673
2674 if options.diff:
2675 options.reporter = DiffReport
2676 stdin = stdin_get_value()
2677 options.selected_lines = parse_udiff(stdin, options.filename, args[0])
2678 args = sorted(options.selected_lines)
2679
2680 return options, args
2681
2682
2683 def _parse_multi_options(options, split_token=','):
2684 r"""Split and strip and discard empties.
2685
2686 Turns the following:
2687
2688 A,
2689 B,
2690
2691 into ["A", "B"]
2692 """
2693 if options:
2694 return [o.strip() for o in options.split(split_token) if o.strip()]
2695 else:
2696 return options
2697
2698
2699 def _main():
2700 """Parse options and run checks on Python source."""
2701 import signal
2702
2703 # Handle "Broken pipe" gracefully
2704 try:
2705 signal.signal(signal.SIGPIPE, lambda signum, frame: sys.exit(1))
2706 except AttributeError:
2707 pass # not supported on Windows
2708
2709 style_guide = StyleGuide(parse_argv=True)
2710 options = style_guide.options
2711
2712 if options.doctest or options.testsuite:
2713 from testsuite.support import run_tests
2714 report = run_tests(style_guide)
2715 else:
2716 report = style_guide.check_files()
2717
2718 if options.statistics:
2719 report.print_statistics()
2720
2721 if options.benchmark:
2722 report.print_benchmark()
2723
2724 if options.testsuite and not options.quiet:
2725 report.print_results()
2726
2727 if report.total_errors:
2728 if options.count:
2729 sys.stderr.write(str(report.total_errors) + '\n')
2730 sys.exit(1)
2731
2732
2733 if __name__ == '__main__':
2734 _main()
2735 #
2736 # eflag: noqa = D2, M601, M701, M702, M801

eric ide

mercurial