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

branch
eric7
changeset 10168
8312e0e76795
parent 9653
e67609152c5e
child 10353
babe9d606903
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/pycodestyle.py	Tue Aug 29 16:50:17 2023 +0200
+++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/pycodestyle.py	Tue Aug 29 16:55:01 2023 +0200
@@ -82,16 +82,16 @@
         sys.version_info < (3, 10) and
         callable(getattr(tokenize, '_compile', None))
 ):  # pragma: no cover (<py310)
-    tokenize._compile = lru_cache()(tokenize._compile)  # type: ignore
+    tokenize._compile = lru_cache(tokenize._compile)  # type: ignore
 
-__version__ = '2.10.0-eric'
+__version__ = '2.11.0-eric'
 
 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox'
 DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503,W504'
 try:
-    if sys.platform == 'win32':
+    if sys.platform == 'win32':  # pragma: win32 cover
         USER_CONFIG = os.path.expanduser(r'~\.pycodestyle')
-    else:
+    else:  # pragma: win32 no cover
         USER_CONFIG = os.path.join(
             os.getenv('XDG_CONFIG_HOME') or os.path.expanduser('~/.config'),
             'pycodestyle'
@@ -100,7 +100,6 @@
     USER_CONFIG = None
 
 PROJECT_CONFIG = ('setup.cfg', 'tox.ini')
-TESTSUITE_PATH = os.path.join(os.path.dirname(__file__), 'testsuite')
 MAX_LINE_LENGTH = 79
 # Number of blank lines between various code parts.
 BLANK_LINES_CONFIG = {
@@ -122,12 +121,10 @@
 UNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-'])
 ARITHMETIC_OP = frozenset(['**', '*', '/', '//', '+', '-', '@'])
 WS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%'])
-ASSIGNMENT_EXPRESSION_OP = [':='] if sys.version_info >= (3, 8) else []
 WS_NEEDED_OPERATORS = frozenset([
-    '**=', '*=', '/=', '//=', '+=', '-=', '!=', '<>', '<', '>',
+    '**=', '*=', '/=', '//=', '+=', '-=', '!=', '<', '>',
     '%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '=',
-    'and', 'in', 'is', 'or', '->'] +
-    ASSIGNMENT_EXPRESSION_OP)
+    'and', 'in', 'is', 'or', '->', ':='])
 WHITESPACE = frozenset(' \t\xa0')
 NEWLINE = frozenset([tokenize.NL, tokenize.NEWLINE])
 SKIP_TOKENS = NEWLINE.union([tokenize.INDENT, tokenize.DEDENT])
@@ -136,8 +133,6 @@
 BENCHMARK_KEYS = ['directories', 'files', 'logical lines', 'physical lines']
 
 INDENT_REGEX = re.compile(r'([ \t]*)')
-RAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,')
-RERAISE_COMMA_REGEX = re.compile(r'raise\s+\w+\s*,.*,\s*\w+\s*$')
 ERRORCODE_REGEX = re.compile(r'\b[A-Z]\d{3}\b')
 DOCSTRING_REGEX = re.compile(r'u?r?["\']')
 EXTRANEOUS_WHITESPACE_REGEX = re.compile(r'[\[({][ \t]|[ \t][\]}),;:](?!=)')
@@ -146,8 +141,10 @@
                                      r'\s*(?(1)|(None|False|True))\b')
 COMPARE_NEGATIVE_REGEX = re.compile(r'\b(?<!is\s)(not)\s+[^][)(}{ ]+\s+'
                                     r'(in|is)\s')
-COMPARE_TYPE_REGEX = re.compile(r'(?:[=!]=|is(?:\s+not)?)\s+type(?:s.\w+Type'
-                                r'|\s*\(\s*([^)]*[^ )])\s*\))')
+COMPARE_TYPE_REGEX = re.compile(
+    r'[=!]=\s+type(?:\s*\(\s*([^)]*[^ )])\s*\))'
+    r'|\btype(?:\s*\(\s*([^)]*[^ )])\s*\))\s+[=!]='
+)
 KEYWORD_REGEX = re.compile(r'(\s*)\b(?:%s)\b(\s*)' % r'|'.join(KEYWORDS))
 OPERATOR_REGEX = re.compile(r'(?:[^,\s])(\s*)(?:[-+*/|!<=>%&^]+|:=)(\s*)')
 LAMBDA_REGEX = re.compile(r'\blambda\b')
@@ -168,6 +165,13 @@
 DUNDER_REGEX = re.compile(r"^__([^\s]+)__(?::\s*[a-zA-Z.0-9_\[\]\"]+)? = ")
 BLANK_EXCEPT_REGEX = re.compile(r"except\s*:")
 
+if sys.version_info >= (3, 12):  # pragma: >=3.12 cover
+    FSTRING_START = tokenize.FSTRING_START
+    FSTRING_MIDDLE = tokenize.FSTRING_MIDDLE
+    FSTRING_END = tokenize.FSTRING_END
+else:  # pragma: <3.12 cover
+    FSTRING_START = FSTRING_MIDDLE = FSTRING_END = -1
+
 _checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
 
 
@@ -214,7 +218,6 @@
     These options are highly recommended!
 
     Okay: if a == 0:\n    a = 1\n    b = 1
-    E101: if a == 0:\n        a = 1\n\tb = 1
     """
     indent = INDENT_REGEX.match(physical_line).group(1)
     for offset, char in enumerate(indent):
@@ -517,7 +520,6 @@
         if (tok0.end == tok1.start and
                 keyword.iskeyword(tok0.string) and
                 tok0.string not in SINGLETONS and
-                tok0.string not in ('async', 'await') and
                 not (tok0.string == 'except' and tok1.string == '*') and
                 not (tok0.string == 'yield' and tok1.string == ')') and
                 tok1.string not in ':\n'):
@@ -525,37 +527,6 @@
 
 
 @register_check
-def missing_whitespace(logical_line):
-    r"""Each comma, semicolon or colon should be followed by whitespace.
-
-    Okay: [a, b]
-    Okay: (3,)
-    Okay: a[3,] = 1
-    Okay: a[1:4]
-    Okay: a[:4]
-    Okay: a[1:]
-    Okay: a[1:4:2]
-    E231: ['a','b']
-    E231: foo(bar,baz)
-    E231: [{'a':'b'}]
-    """
-    line = logical_line
-    for index in range(len(line) - 1):
-        char = line[index]
-        next_char = line[index + 1]
-        if char in ',;:' and next_char not in WHITESPACE:
-            before = line[:index]
-            if char == ':' and before.count('[') > before.count(']') and \
-                    before.rfind('{') < before.rfind('['):
-                continue  # Slice syntax, no space required
-            if char == ',' and next_char in ')]':
-                continue  # Allow tuple with only one element: (3,)
-            if char == ':' and next_char == '=' and sys.version_info >= (3, 8):
-                continue  # Allow assignment expression
-            yield index, "E231 missing whitespace after '%s'", char
-
-
-@register_check
 def indentation(logical_line, previous_logical, indent_char,
                 indent_level, previous_indent_level,
                 indent_size):
@@ -743,8 +714,7 @@
             if verbose >= 4:
                 print(f"bracket depth {depth} indent to {start[1]}")
         # deal with implicit string concatenation
-        elif (token_type in (tokenize.STRING, tokenize.COMMENT) or
-              text in ('u', 'ur', 'b', 'br')):
+        elif token_type in (tokenize.STRING, tokenize.COMMENT, FSTRING_START):
             indent_chances[start[1]] = str
         # visual indent after assert/raise/with
         elif not row and not depth and text in ["assert", "raise", "with"]:
@@ -832,9 +802,10 @@
             (index < 2 or tokens[index - 2][1] != 'class') and
             # Allow "return (a.foo for a in range(5))"
             not keyword.iskeyword(prev_text) and
-            # 'match' and 'case' are only soft keywords
             (
                 sys.version_info < (3, 9) or
+                # 3.12+: type is a soft keyword but no braces after
+                prev_text == 'type' or
                 not keyword.issoftkeyword(prev_text)
             )
         ):
@@ -869,14 +840,16 @@
 
 
 @register_check
-def missing_whitespace_around_operator(logical_line, tokens):
-    r"""Surround operators with a single space on either side.
+def missing_whitespace(logical_line, tokens):
+    r"""Surround operators with the correct amount of whitespace.
 
     - Always surround these binary operators with a single space on
       either side: assignment (=), augmented assignment (+=, -= etc.),
       comparisons (==, <, >, !=, <=, >=, in, not in, is, is not),
       Booleans (and, or, not).
 
+    - Each comma, semicolon or colon should be followed by whitespace.
+
     - If operators with different priorities are used, consider adding
       whitespace around the operators with the lowest priorities.
 
@@ -887,6 +860,13 @@
     Okay: c = (a + b) * (a - b)
     Okay: foo(bar, key='word', *args, **kwargs)
     Okay: alpha[:-i]
+    Okay: [a, b]
+    Okay: (3,)
+    Okay: a[3,] = 1
+    Okay: a[1:4]
+    Okay: a[:4]
+    Okay: a[1:]
+    Okay: a[1:4:2]
 
     E225: i=i+1
     E225: submitted +=1
@@ -897,19 +877,52 @@
     E226: hypot2 = x*x + y*y
     E227: c = a|b
     E228: msg = fmt%(errno, errmsg)
+    E231: ['a','b']
+    E231: foo(bar,baz)
+    E231: [{'a':'b'}]
     """
-    parens = 0
     need_space = False
     prev_type = tokenize.OP
     prev_text = prev_end = None
     operator_types = (tokenize.OP, tokenize.NAME)
+    brace_stack = []
     for token_type, text, start, end, line in tokens:
+        if token_type == tokenize.OP and text in {'[', '(', '{'}:
+            brace_stack.append(text)
+        elif token_type == FSTRING_START:  # pragma: >=3.12 cover
+            brace_stack.append('f')
+        elif token_type == tokenize.NAME and text == 'lambda':
+            brace_stack.append('l')
+        elif brace_stack:
+            if token_type == tokenize.OP and text in {']', ')', '}'}:
+                brace_stack.pop()
+            elif token_type == FSTRING_END:  # pragma: >=3.12 cover
+                brace_stack.pop()
+            elif (
+                    brace_stack[-1] == 'l' and
+                    token_type == tokenize.OP and
+                    text == ':'
+            ):
+                brace_stack.pop()
+
         if token_type in SKIP_COMMENTS:
             continue
-        if text in ('(', 'lambda'):
-            parens += 1
-        elif text == ')':
-            parens -= 1
+
+        if token_type == tokenize.OP and text in {',', ';', ':'}:
+            next_char = line[end[1]:end[1] + 1]
+            if next_char not in WHITESPACE and next_char not in '\r\n':
+                # slice
+                if text == ':' and brace_stack[-1:] == ['[']:
+                    pass
+                # 3.12+ fstring format specifier
+                elif text == ':' and brace_stack[-2:] == ['f', '{']:  # pragma: >=3.12 cover  # noqa: E501
+                    pass
+                # tuple (and list for some reason?)
+                elif text == ',' and next_char in ')]':
+                    pass
+                else:
+                    yield start, f'E231 missing whitespace after {text!r}', text
+
         if need_space:
             if start != prev_end:
                 # Found a (probably) needed space
@@ -917,10 +930,6 @@
                     yield (need_space[0],
                            "E225 missing whitespace around operator")
                 need_space = False
-            elif text == '>' and prev_text in ('<', '-'):
-                # Tolerate the "<>" operator, even if running Python 3
-                # Deal with Python 3's annotated return value "->"
-                pass
             elif (
                     # def f(a, /, b):
                     #           ^
@@ -950,8 +959,16 @@
                            "around %s operator" % (code, optype))
                 need_space = False
         elif token_type in operator_types and prev_end is not None:
-            if text == '=' and parens:
-                # Allow keyword args or defaults: foo(bar=None).
+            if (
+                    text == '=' and (
+                        # allow lambda default args: lambda x=None: None
+                        brace_stack[-1:] == ['l'] or
+                        # allow keyword args or defaults: foo(bar=None).
+                        brace_stack[-1:] == ['('] or
+                        # allow python 3.8 fstring repr specifier
+                        brace_stack[-2:] == ['f', '{']
+                    )
+            ):
                 pass
             elif text in WS_NEEDED_OPERATORS:
                 need_space = True
@@ -1145,10 +1162,6 @@
     Okay: # this is a comment\nimport os
     Okay: '''this is a module docstring'''\nimport os
     Okay: r'''this is a module docstring'''\nimport os
-    Okay:  
-    try:\n\timport x\nexcept ImportError:\n\tpass\nelse:\n\tpass\nimport y
-    Okay:  
-    try:\n\timport x\nexcept ImportError:\n\tpass\nfinally:\n\tpass\nimport y
     E402: a=1\nimport os
     E402: 'One string'\n"Two string"\nimport os
     E402: a=1\nfrom sys import x
@@ -1229,11 +1242,12 @@
     counts = {char: 0 for char in '{}[]()'}
     while -1 < found < last_char:
         update_counts(line[prev_found:found], counts)
-        if ((counts['{'] <= counts['}'] and   # {'a': 1} (dict)
-             counts['['] <= counts[']'] and   # [1:2] (slice)
-             counts['('] <= counts[')']) and  # (annotation)
-            not (sys.version_info >= (3, 8) and
-                 line[found + 1] == '=')):  # assignment expression
+        if (
+                counts['{'] <= counts['}'] and  # {'a': 1} (dict)
+                counts['['] <= counts[']'] and  # [1:2] (slice)
+                counts['('] <= counts[')'] and  # (annotation)
+                line[found + 1] != '='  # assignment expression
+        ):
             lambda_kw = LAMBDA_REGEX.search(line, 0, found)
             if lambda_kw:
                 before = line[:lambda_kw.start()].rstrip()
@@ -1469,21 +1483,19 @@
     Do not compare types directly.
 
     Okay: if isinstance(obj, int):
-    E721: if type(obj) is type(1):
-
-    When checking if an object is a string, keep in mind that it might
-    be a unicode string too! In Python 2.3, str and unicode have a
-    common base class, basestring, so you can do:
-
-    Okay: if isinstance(obj, basestring):
-    Okay: if type(a1) is type(b1):
+    Okay: if type(obj) is int:
+    E721: if type(obj) == type(1):
     """
     match = COMPARE_TYPE_REGEX.search(logical_line)
     if match and not noqa:
         inst = match.group(1)
         if inst and inst.isidentifier() and inst not in SINGLETONS:
             return  # Allow comparison for types which are not obvious
-        yield match.start(), "E721 do not compare types, use 'isinstance()'"
+        yield (
+            match.start(),
+            "E721 do not compare types, for exact checks use `is` / `is not`, "
+            "for instance checks use `isinstance()`",
+        )
 
 
 @register_check
@@ -1604,59 +1616,6 @@
 
 
 @register_check
-def python_3000_has_key(logical_line, noqa):
-    r"""The {}.has_key() method is removed in Python 3: use the 'in'
-    operator.
-
-    Okay: if "alph" in d:\n    print d["alph"]
-    W601: assert d.has_key('alph')
-    """
-    pos = logical_line.find('.has_key(')
-    if pos > -1 and not noqa:
-        yield pos, "W601 .has_key() is deprecated, use 'in'"
-
-
-@register_check
-def python_3000_raise_comma(logical_line):
-    r"""When raising an exception, use "raise ValueError('message')".
-
-    The older form is removed in Python 3.
-
-    Okay: raise DummyError("Message")
-    W602: raise DummyError, "Message"
-    """
-    match = RAISE_COMMA_REGEX.match(logical_line)
-    if match and not RERAISE_COMMA_REGEX.match(logical_line):
-        yield match.end() - 1, "W602 deprecated form of raising exception"
-
-
-@register_check
-def python_3000_not_equal(logical_line):
-    r"""New code should always use != instead of <>.
-
-    The older syntax is removed in Python 3.
-
-    Okay: if a != 'no':
-    W603: if a <> 'no':
-    """
-    pos = logical_line.find('<>')
-    if pos > -1:
-        yield pos, "W603 '<>' is deprecated, use '!='"
-
-
-@register_check
-def python_3000_backticks(logical_line):
-    r"""Use repr() instead of backticks in Python 3.
-
-    Okay: val = repr(1 + 2)
-    W604: val = `1 + 2`
-    """
-    pos = logical_line.find('`')
-    if pos > -1:
-        yield pos, "W604 backticks are deprecated, use 'repr()'"
-
-
-@register_check
 def python_3000_invalid_escape_sequence(logical_line, tokens, noqa):
     r"""Invalid escape sequences are deprecated in Python 3.6.
 
@@ -1688,102 +1647,33 @@
         'U',
     ]
 
-    for token_type, text, start, end, line in tokens:
-        if token_type == tokenize.STRING:
-            start_line, start_col = start
-            quote = text[-3:] if text[-3:] in ('"""', "'''") else text[-1]
+    prefixes = []
+    for token_type, text, start, _, _ in tokens:
+        if token_type in {tokenize.STRING, FSTRING_START}:
             # Extract string modifiers (e.g. u or r)
-            quote_pos = text.index(quote)
-            prefix = text[:quote_pos].lower()
-            start = quote_pos + len(quote)
-            string = text[start:-len(quote)]
+            prefixes.append(text[:text.index(text[-1])].lower())
 
-            if 'r' not in prefix:
-                pos = string.find('\\')
+        if token_type in {tokenize.STRING, FSTRING_MIDDLE}:
+            if 'r' not in prefixes[-1]:
+                start_line, start_col = start
+                pos = text.find('\\')
                 while pos >= 0:
                     pos += 1
-                    if string[pos] not in valid:
-                        line = start_line + string.count('\n', 0, pos)
+                    if text[pos] not in valid:
+                        line = start_line + text.count('\n', 0, pos)
                         if line == start_line:
-                            col = start_col + len(prefix) + len(quote) + pos
+                            col = start_col + pos
                         else:
-                            col = pos - string.rfind('\n', 0, pos) - 1
+                            col = pos - text.rfind('\n', 0, pos) - 1
                         yield (
                             (line, col - 1),
-                            "W605 invalid escape sequence '\\%s'",
-                            string[pos],
+                            f"W605 invalid escape sequence '\\{text[pos]}'",
+                            text[pos],
                         )
-                    pos = string.find('\\', pos + 1)
-
-
-@register_check
-def python_3000_async_await_keywords(logical_line, tokens):
-    """'async' and 'await' are reserved keywords starting at Python 3.7.
-
-    W606: async = 42
-    W606: await = 42
-    Okay: async def read(db):\n    data = await db.fetch('SELECT ...')
-    """
-    # The Python tokenize library before Python 3.5 recognizes
-    # async/await as a NAME token. Therefore, use a state machine to
-    # look for the possible async/await constructs as defined by the
-    # Python grammar:
-    # https://docs.python.org/3/reference/grammar.html
-
-    state = None
-    for token_type, text, start, end, line in tokens:
-        error = False
-
-        if token_type == tokenize.NL:
-            continue
-
-        if state is None:
-            if token_type == tokenize.NAME:
-                if text == 'async':
-                    state = ('async_stmt', start)
-                elif text == 'await':
-                    state = ('await', start)
-                elif (token_type == tokenize.NAME and
-                      text in ('def', 'for')):
-                    state = ('define', start)
+                    pos = text.find('\\', pos + 1)
 
-        elif state[0] == 'async_stmt':
-            if token_type == tokenize.NAME and text in ('def', 'with', 'for'):
-                # One of funcdef, with_stmt, or for_stmt. Return to
-                # looking for async/await names.
-                state = None
-            else:
-                error = True
-        elif state[0] == 'await':
-            if token_type == tokenize.NAME:
-                # An await expression. Return to looking for async/await
-                # names.
-                state = None
-            elif token_type == tokenize.OP and text == '(':
-                state = None
-            else:
-                error = True
-        elif state[0] == 'define':
-            if token_type == tokenize.NAME and text in ('async', 'await'):
-                error = True
-            else:
-                state = None
-
-        if error:
-            yield (
-                state[1],
-                "W606 'async' and 'await' are reserved keywords starting with "
-                "Python 3.7",
-            )
-            state = None
-
-    # Last token
-    if state is not None:
-        yield (
-            state[1],
-            "W606 'async' and 'await' are reserved keywords starting with "
-            "Python 3.7",
-        )
+        if token_type in {tokenize.STRING, FSTRING_END}:
+            prefixes.pop()
 
 
 ########################################################################
@@ -1861,15 +1751,6 @@
     r"""Return the amount of indentation.
 
     Tabs are expanded to the next multiple of 8.
-
-    >>> expand_indent('    ')
-    4
-    >>> expand_indent('\t')
-    8
-    >>> expand_indent('       \t')
-    8
-    >>> expand_indent('        \t')
-    16
     """
     line = line.rstrip('\n\r')
     if '\t' not in line:
@@ -1886,15 +1767,7 @@
 
 
 def mute_string(text):
-    """Replace contents with 'xxx' to prevent syntax matching.
-
-    >>> mute_string('"abc"')
-    '"xxx"'
-    >>> mute_string("'''abc'''")
-    "'''xxx'''"
-    >>> mute_string("r'abc'")
-    "r'xxx'"
-    """
+    """Replace contents with 'xxx' to prevent syntax matching."""
     # String modifiers (e.g. u or r)
     start = text.index(text[-1]) + 1
     end = len(text) - 1
@@ -1995,6 +1868,7 @@
         self.max_line_length = options.max_line_length
         self.max_doc_length = options.max_doc_length
         self.indent_size = options.indent_size
+        self.fstring_start = 0
         self.multiline = False  # in a multiline string?
         self.hang_closing = options.hang_closing
         self.indent_size = options.indent_size
@@ -2097,6 +1971,8 @@
                 continue
             if token_type == tokenize.STRING:
                 text = mute_string(text)
+            elif token_type == FSTRING_MIDDLE:  # pragma: >=3.12 cover
+                text = 'x' * len(text)
             if prev_row:
                 (start_row, start_col) = start
                 if prev_row != start_row:    # different row
@@ -2187,16 +2063,21 @@
         """If appropriate for token, check current physical line(s)."""
         # Called after every token, but act only on end of line.
 
+        if token.type == FSTRING_START:  # pragma: >=3.12 cover
+            self.fstring_start = token.start[0]
         # a newline token ends a single physical line.
-        if _is_eol_token(token):
+        elif _is_eol_token(token):
             # if the file does not end with a newline, the NEWLINE
             # token is inserted by the parser, but it does not contain
             # the previous physical line in `token[4]`
-            if token[4] == '':
+            if token.line == '':
                 self.check_physical(prev_physical)
             else:
-                self.check_physical(token[4])
-        elif token[0] == tokenize.STRING and '\n' in token[1]:
+                self.check_physical(token.line)
+        elif (
+                token.type == tokenize.STRING and '\n' in token.string or
+                token.type == FSTRING_END
+        ):
             # Less obviously, a string that contains newlines is a
             # multiline string, either triple-quoted or with internal
             # newlines backslash-escaped. Check every physical line in
@@ -2212,14 +2093,18 @@
             # - have to wind self.line_number back because initially it
             #   points to the last line of the string, and we want
             #   check_physical() to give accurate feedback
-            if noqa(token[4]):
+            if noqa(token.line):
                 return
+            if token.type == FSTRING_END:  # pragma: >=3.12 cover
+                start = self.fstring_start
+            else:
+                start = token.start[0]
+            end = token.end[0]
+
             self.multiline = True
-            self.line_number = token[2][0]
-            _, src, (_, offset), _, _ = token
-            src = self.lines[self.line_number - 1][:offset] + src
-            for line in src.split('\n')[:-1]:
-                self.check_physical(line + '\n')
+            self.line_number = start
+            for line_number in range(start, end):
+                self.check_physical(self.lines[line_number - 1] + '\n')
                 self.line_number += 1
             self.multiline = False
 
@@ -2487,15 +2372,13 @@
             options.reporter = BaseReport if options.quiet else StandardReport
 
         options.select = tuple(options.select or ())
-#        if not (options.select or options.ignore or
-#                options.testsuite or options.doctest) and DEFAULT_IGNORE:
+#        if not (options.select or options.ignore) and DEFAULT_IGNORE:
 #            # The default choice: ignore controversial checks
 #            options.ignore = tuple(DEFAULT_IGNORE.split(','))
 #        else:
-#            # Ignore all checks which are not explicitly selected or all if no
+#            # Ignore all checks which are not explicitly selected
 #            options.ignore = ('',) if options.select else tuple(options.ignore)
 
-        # check is ignored or explicitly selected
         options.ignore = ('',) if options.select else tuple(options.ignore)
         options.benchmark_keys = BENCHMARK_KEYS[:]
         options.ignore_code = self.ignore_code
@@ -2661,11 +2544,6 @@
                       help="report changes only within line number ranges in "
                            "the unified diff received on STDIN")
     group = parser.add_option_group("Testing Options")
-    if os.path.exists(TESTSUITE_PATH):
-        group.add_option('--testsuite', metavar='dir',
-                         help="run regression tests from dir")
-        group.add_option('--doctest', action='store_true',
-                         help="run doctest on myself")
     group.add_option('--benchmark', action='store_true',
                      help="measure processing speed")
     return parser
@@ -2742,7 +2620,6 @@
 
         # Third, overwrite with the command-line options
         (options, __) = parser.parse_args(arglist, values=new_options)
-    options.doctest = options.testsuite = False
     return options
 
 
@@ -2775,17 +2652,14 @@
     if verbose is not None:
         options.verbose = verbose
 
-    if options.ensure_value('testsuite', False):
-        args.append(options.testsuite)
-    elif not options.ensure_value('doctest', False):
-        if parse_argv and not args:
-            if options.diff or any(os.path.exists(name)
-                                   for name in PROJECT_CONFIG):
-                args = ['.']
-            else:
-                parser.error('input not specified')
-        options = read_config(options, args, arglist, parser)
-        options.reporter = parse_argv and options.quiet == 1 and FileReport
+    if parse_argv and not args:
+        if options.diff or any(os.path.exists(name)
+                               for name in PROJECT_CONFIG):
+            args = ['.']
+        else:
+            parser.error('input not specified')
+    options = read_config(options, args, arglist, parser)
+    options.reporter = parse_argv and options.quiet == 1 and FileReport
 
     options.filename = _parse_multi_options(options.filename)
     options.exclude = normalize_paths(options.exclude)
@@ -2830,11 +2704,7 @@
     style_guide = StyleGuide(parse_argv=True)
     options = style_guide.options
 
-    if options.doctest or options.testsuite:
-        from testsuite.support import run_tests
-        report = run_tests(style_guide)
-    else:
-        report = style_guide.check_files()
+    report = style_guide.check_files()
 
     if options.statistics:
         report.print_statistics()
@@ -2842,9 +2712,6 @@
     if options.benchmark:
         report.print_benchmark()
 
-    if options.testsuite and not options.quiet:
-        report.print_results()
-
     if report.total_errors:
         if options.count:
             sys.stderr.write(str(report.total_errors) + '\n')

eric ide

mercurial