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

branch
eric7
changeset 9592
2b3802c3c6d2
parent 9375
e21b51a3d990
child 9653
e67609152c5e
equal deleted inserted replaced
9591:3c56c81a70be 9592:2b3802c3c6d2
60 # 60 #
61 # Copyright (c) 2011 - 2022 Detlev Offenbach <detlev@die-offenbachs.de> 61 # Copyright (c) 2011 - 2022 Detlev Offenbach <detlev@die-offenbachs.de>
62 # 62 #
63 63
64 import bisect 64 import bisect
65 import configparser
65 import inspect 66 import inspect
67 import io
66 import keyword 68 import keyword
67 import os 69 import os
68 import re 70 import re
69 import sys 71 import sys
70 import time 72 import time
73 75
74 from fnmatch import fnmatch 76 from fnmatch import fnmatch
75 from functools import lru_cache 77 from functools import lru_cache
76 from optparse import OptionParser 78 from optparse import OptionParser
77 79
78 try:
79 from configparser import RawConfigParser
80 from io import TextIOWrapper
81 except ImportError:
82 from ConfigParser import RawConfigParser # __IGNORE_WARNING__
83
84 # this is a performance hack. see https://bugs.python.org/issue43014 80 # this is a performance hack. see https://bugs.python.org/issue43014
85 if ( 81 if (
86 sys.version_info < (3, 10) and 82 sys.version_info < (3, 10) and
87 callable(getattr(tokenize, '_compile', None)) 83 callable(getattr(tokenize, '_compile', None))
88 ): # pragma: no cover (<py310) 84 ): # pragma: no cover (<py310)
89 tokenize._compile = lru_cache()(tokenize._compile) # type: ignore 85 tokenize._compile = lru_cache()(tokenize._compile) # type: ignore
90 86
91 __version__ = '2.9.1-eric' 87 __version__ = '2.10.0-eric'
92 88
93 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox' 89 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox'
94 DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503,W504' 90 DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503,W504'
95 try: 91 try:
96 if sys.platform == 'win32': 92 if sys.platform == 'win32':
532 def missing_whitespace(logical_line): 528 def missing_whitespace(logical_line):
533 r"""Each comma, semicolon or colon should be followed by whitespace. 529 r"""Each comma, semicolon or colon should be followed by whitespace.
534 530
535 Okay: [a, b] 531 Okay: [a, b]
536 Okay: (3,) 532 Okay: (3,)
533 Okay: a[3,] = 1
537 Okay: a[1:4] 534 Okay: a[1:4]
538 Okay: a[:4] 535 Okay: a[:4]
539 Okay: a[1:] 536 Okay: a[1:]
540 Okay: a[1:4:2] 537 Okay: a[1:4:2]
541 E231: ['a','b'] 538 E231: ['a','b']
549 if char in ',;:' and next_char not in WHITESPACE: 546 if char in ',;:' and next_char not in WHITESPACE:
550 before = line[:index] 547 before = line[:index]
551 if char == ':' and before.count('[') > before.count(']') and \ 548 if char == ':' and before.count('[') > before.count(']') and \
552 before.rfind('{') < before.rfind('['): 549 before.rfind('{') < before.rfind('['):
553 continue # Slice syntax, no space required 550 continue # Slice syntax, no space required
554 if char == ',' and next_char == ')': 551 if char == ',' and next_char in ')]':
555 continue # Allow tuple with only one element: (3,) 552 continue # Allow tuple with only one element: (3,)
556 if char == ':' and next_char == '=' and sys.version_info >= (3, 8): 553 if char == ':' and next_char == '=' and sys.version_info >= (3, 8):
557 continue # Allow assignment expression 554 continue # Allow assignment expression
558 yield index, "E231 missing whitespace after '%s'", char 555 yield index, "E231 missing whitespace after '%s'", char
559 556
1519 E741: l = 0 1516 E741: l = 0
1520 E741: O = 123 1517 E741: O = 123
1521 E741: I = 42 1518 E741: I = 42
1522 1519
1523 Variables can be bound in several other contexts, including class 1520 Variables can be bound in several other contexts, including class
1524 and function definitions, 'global' and 'nonlocal' statements, 1521 and function definitions, lambda functions, 'global' and 'nonlocal'
1525 exception handlers, and 'with' and 'for' statements. 1522 statements, exception handlers, and 'with' and 'for' statements.
1526 In addition, we have a special handling for function parameters. 1523 In addition, we have a special handling for function parameters.
1527 1524
1528 Okay: except AttributeError as o: 1525 Okay: except AttributeError as o:
1529 Okay: with lock as L: 1526 Okay: with lock as L:
1530 Okay: foo(l=12) 1527 Okay: foo(l=12)
1528 Okay: foo(l=I)
1531 Okay: for a in foo(l=12): 1529 Okay: for a in foo(l=12):
1530 Okay: lambda arg: arg * l
1531 Okay: lambda a=l[I:5]: None
1532 Okay: lambda x=a.I: None
1533 Okay: if l >= 12:
1532 E741: except AttributeError as O: 1534 E741: except AttributeError as O:
1533 E741: with lock as l: 1535 E741: with lock as l:
1534 E741: global I 1536 E741: global I
1535 E741: nonlocal l 1537 E741: nonlocal l
1536 E741: def foo(l): 1538 E741: def foo(l):
1537 E741: def foo(l=12): 1539 E741: def foo(l=12):
1538 E741: l = foo(l=12) 1540 E741: l = foo(l=12)
1539 E741: for l in range(10): 1541 E741: for l in range(10):
1542 E741: [l for l in lines if l]
1543 E741: lambda l: None
1544 E741: lambda a=x[1:5], l: None
1545 E741: lambda **l:
1546 E741: def f(**l):
1540 E742: class I(object): 1547 E742: class I(object):
1541 E743: def l(x): 1548 E743: def l(x):
1542 """ 1549 """
1543 is_func_def = False # Set to true if 'def' is found 1550 func_depth = None # set to brace depth if 'def' or 'lambda' is found
1544 parameter_parentheses_level = 0 1551 seen_colon = False # set to true if we're done with function parameters
1552 brace_depth = 0
1545 idents_to_avoid = ('l', 'O', 'I') 1553 idents_to_avoid = ('l', 'O', 'I')
1546 prev_type, prev_text, prev_start, prev_end, __ = tokens[0] 1554 prev_type, prev_text, prev_start, prev_end, __ = tokens[0]
1547 for token_type, text, start, end, line in tokens[1:]: 1555 for index in range(1, len(tokens)):
1556 token_type, text, start, end, line = tokens[index]
1548 ident = pos = None 1557 ident = pos = None
1549 # find function definitions 1558 # find function definitions
1550 if prev_text == 'def': 1559 if prev_text in {'def', 'lambda'}:
1551 is_func_def = True 1560 func_depth = brace_depth
1561 seen_colon = False
1562 elif (
1563 func_depth is not None and
1564 text == ':' and
1565 brace_depth == func_depth
1566 ):
1567 seen_colon = True
1552 # update parameter parentheses level 1568 # update parameter parentheses level
1553 if parameter_parentheses_level == 0 and \ 1569 if text in '([{':
1554 prev_type == tokenize.NAME and \ 1570 brace_depth += 1
1555 token_type == tokenize.OP and text == '(': 1571 elif text in ')]}':
1556 parameter_parentheses_level = 1 1572 brace_depth -= 1
1557 elif parameter_parentheses_level > 0 and \
1558 token_type == tokenize.OP:
1559 if text == '(':
1560 parameter_parentheses_level += 1
1561 elif text == ')':
1562 parameter_parentheses_level -= 1
1563 # identifiers on the lhs of an assignment operator 1573 # identifiers on the lhs of an assignment operator
1564 if token_type == tokenize.OP and '=' in text and \ 1574 if text == ':=' or (text == '=' and brace_depth == 0):
1565 parameter_parentheses_level == 0:
1566 if prev_text in idents_to_avoid: 1575 if prev_text in idents_to_avoid:
1567 ident = prev_text 1576 ident = prev_text
1568 pos = prev_start 1577 pos = prev_start
1569 # identifiers bound to values with 'as', 'for', 1578 # identifiers bound to values with 'as', 'for',
1570 # 'global', or 'nonlocal' 1579 # 'global', or 'nonlocal'
1571 if prev_text in ('as', 'for', 'global', 'nonlocal'): 1580 if prev_text in ('as', 'for', 'global', 'nonlocal'):
1572 if text in idents_to_avoid: 1581 if text in idents_to_avoid:
1573 ident = text 1582 ident = text
1574 pos = start 1583 pos = start
1575 # function parameter definitions 1584 # function / lambda parameter definitions
1576 if is_func_def: 1585 if (
1577 if text in idents_to_avoid: 1586 func_depth is not None and
1578 ident = text 1587 not seen_colon and
1579 pos = start 1588 index < len(tokens) - 1 and tokens[index + 1][1] in ':,=)' and
1589 prev_text in {'lambda', ',', '*', '**', '('} and
1590 text in idents_to_avoid
1591 ):
1592 ident = text
1593 pos = start
1580 if prev_text == 'class': 1594 if prev_text == 'class':
1581 if text in idents_to_avoid: 1595 if text in idents_to_avoid:
1582 yield start, "E742 ambiguous class definition '%s'", text 1596 yield start, "E742 ambiguous class definition '%s'", text
1583 if prev_text == 'def': 1597 if prev_text == 'def':
1584 if text in idents_to_avoid: 1598 if text in idents_to_avoid:
1585 yield start, "E743 ambiguous function definition '%s'", text 1599 yield start, "E743 ambiguous function definition '%s'", text
1586 if ident: 1600 if ident:
1587 yield pos, "E741 ambiguous variable name '%s'", ident 1601 yield pos, "E741 ambiguous variable name '%s'", ident
1588 prev_type = token_type
1589 prev_text = text 1602 prev_text = text
1590 prev_start = start 1603 prev_start = start
1591 1604
1592 1605
1593 @register_check 1606 @register_check
1837 with open(filename, encoding='latin-1') as f: 1850 with open(filename, encoding='latin-1') as f:
1838 return f.readlines() 1851 return f.readlines()
1839 1852
1840 def stdin_get_value(): 1853 def stdin_get_value():
1841 """Read the value from stdin.""" 1854 """Read the value from stdin."""
1842 return TextIOWrapper(sys.stdin.buffer, errors='ignore').read() 1855 return io.TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
1843 1856
1844 noqa = lru_cache(512)(re.compile(r'# no(?:qa|pep8)\b', re.I).search) 1857 noqa = lru_cache(512)(re.compile(r'# no(?:qa|pep8)\b', re.I).search)
1845 1858
1846 1859
1847 def expand_indent(line): 1860 def expand_indent(line):
2667 Otherwise, the user configuration (~/.config/pycodestyle) and any 2680 Otherwise, the user configuration (~/.config/pycodestyle) and any
2668 local configurations in the current directory or above will be 2681 local configurations in the current directory or above will be
2669 merged together (in that order) using the read method of 2682 merged together (in that order) using the read method of
2670 ConfigParser. 2683 ConfigParser.
2671 """ 2684 """
2672 config = RawConfigParser() 2685 config = configparser.RawConfigParser()
2673 2686
2674 cli_conf = options.config 2687 cli_conf = options.config
2675 2688
2676 local_dir = os.curdir 2689 local_dir = os.curdir
2677 2690

eric ide

mercurial