src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/pycodestyle.py

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

eric ide

mercurial