Third Party packages eric7

Sat, 01 Oct 2022 19:42:50 +0200

author
Detlev Offenbach <detlev@die-offenbachs.de>
date
Sat, 01 Oct 2022 19:42:50 +0200
branch
eric7
changeset 9375
e21b51a3d990
parent 9374
ed79209469ad
child 9376
e143a7e7254b

Third Party packages
- upgraded pycodestyle to version 2.9.1

docs/changelog file | annotate | diff | comparison | revisions
src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/pycodestyle.py file | annotate | diff | comparison | revisions
--- a/docs/changelog	Sat Oct 01 17:37:10 2022 +0200
+++ b/docs/changelog	Sat Oct 01 19:42:50 2022 +0200
@@ -4,6 +4,7 @@
 - bug fixes
 - Third Party packages
   -- upgraded coverage to 6.5.0
+  -- upgraded pycodestyle to version 2.9.1
 
 Version 22.10:
 - bug fixes
--- a/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/pycodestyle.py	Sat Oct 01 17:37:10 2022 +0200
+++ b/src/eric7/Plugins/CheckerPlugins/CodeStyleChecker/pycodestyle.py	Sat Oct 01 19:42:50 2022 +0200
@@ -71,17 +71,8 @@
 import tokenize
 import warnings
 
-try:
-    from functools import lru_cache
-except ImportError:
-    def lru_cache(maxsize=128):  # noqa as it's a fake implementation.
-        """Does not really need a real a lru_cache, it's just
-        optimization, so let's just do nothing here. Python 3.2+ will
-        just get better performances, time to upgrade?
-        """
-        return lambda function: function
-
 from fnmatch import fnmatch
+from functools import lru_cache
 from optparse import OptionParser
 
 try:
@@ -97,7 +88,7 @@
 ):  # pragma: no cover (<py310)
     tokenize._compile = lru_cache()(tokenize._compile)  # type: ignore
 
-__version__ = '2.8.0-eric'
+__version__ = '2.9.1-eric'
 
 DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox'
 DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503,W504'
@@ -135,16 +126,13 @@
 UNARY_OPERATORS = frozenset(['>>', '**', '*', '+', '-'])
 ARITHMETIC_OP = frozenset(['**', '*', '/', '//', '+', '-', '@'])
 WS_OPTIONAL_OPERATORS = ARITHMETIC_OP.union(['^', '&', '|', '<<', '>>', '%'])
-# Warn for -> function annotation operator in py3.5+ (issue 803)
-FUNCTION_RETURN_ANNOTATION_OP = ['->'] if sys.version_info >= (3, 5) else []
 ASSIGNMENT_EXPRESSION_OP = [':='] if sys.version_info >= (3, 8) else []
 WS_NEEDED_OPERATORS = frozenset([
     '**=', '*=', '/=', '//=', '+=', '-=', '!=', '<>', '<', '>',
     '%=', '^=', '&=', '|=', '==', '<=', '>=', '<<=', '>>=', '=',
-    'and', 'in', 'is', 'or'] +
-    FUNCTION_RETURN_ANNOTATION_OP +
+    'and', 'in', 'is', 'or', '->'] +
     ASSIGNMENT_EXPRESSION_OP)
-WHITESPACE = frozenset(' \t')
+WHITESPACE = frozenset(' \t\xa0')
 NEWLINE = frozenset([tokenize.NL, tokenize.NEWLINE])
 SKIP_TOKENS = NEWLINE.union([tokenize.INDENT, tokenize.DEDENT])
 # ERRORTOKEN is triggered by backticks in Python 3
@@ -165,13 +153,13 @@
 COMPARE_TYPE_REGEX = re.compile(r'(?:[=!]=|is(?:\s+not)?)\s+type(?:s.\w+Type'
                                 r'|\s*\(\s*([^)]*[^ )])\s*\))')
 KEYWORD_REGEX = re.compile(r'(\s*)\b(?:%s)\b(\s*)' % r'|'.join(KEYWORDS))
-OPERATOR_REGEX = re.compile(r'(?:[^,\s])(\s*)(?:[-+*/|!<=>%&^]+)(\s*)')
+OPERATOR_REGEX = re.compile(r'(?:[^,\s])(\s*)(?:[-+*/|!<=>%&^]+|:=)(\s*)')
 LAMBDA_REGEX = re.compile(r'\blambda\b')
 HUNK_REGEX = re.compile(r'^@@ -\d+(?:,\d+)? \+(\d+)(?:,(\d+))? @@.*$')
 STARTSWITH_DEF_REGEX = re.compile(r'^(async\s+def|def)\b')
 STARTSWITH_TOP_LEVEL_REGEX = re.compile(r'^(async\s+def\s+|def\s+|class\s+|@)')
 STARTSWITH_INDENT_STATEMENT_REGEX = re.compile(
-    r'^\s*({0})\b'.format('|'.join(s.replace(' ', r'\s+') for s in (
+    r'^\s*({})\b'.format('|'.join(s.replace(' ', r'\s+') for s in (
         'def', 'async def',
         'for', 'async for',
         'if', 'elif', 'else',
@@ -188,13 +176,10 @@
 
 
 def _get_parameters(function):
-    if sys.version_info >= (3, 3):
-        return [parameter.name
-                for parameter
-                in inspect.signature(function).parameters.values()
-                if parameter.kind == parameter.POSITIONAL_OR_KEYWORD]
-    else:
-        return inspect.getargspec(function)[0]
+    return [parameter.name
+            for parameter
+            in inspect.signature(function).parameters.values()
+            if parameter.kind == parameter.POSITIONAL_OR_KEYWORD]
 
 
 def register_check(check, codes=None):
@@ -320,12 +305,6 @@
             (len(chunks) == 2 and chunks[0] == '#')) and \
                 len(line) - len(chunks[-1]) < max_line_length - 7:
             return
-        if hasattr(line, 'decode'):   # Python 2
-            # The line could contain multi-byte characters
-            try:
-                length = len(line.decode('utf-8'))
-            except UnicodeError:
-                pass
         if length > max_line_length:
             return (max_line_length, "E501 line too long "
                     "(%d > %d characters)" % (length, max_line_length),
@@ -450,22 +429,22 @@
                         if nested or ancestor_level == 0:
                             break
                 if nested:
-                    yield (0, "E306 expected %s blank lines before a "
-                        "nested definition, found %d", method_lines,
+                    yield (0, "E306 expected {} blank lines before a "
+                        "nested definition, found {}", method_lines,
                         blank_before)
                 else:
-                    yield (0, "E301 expected %s blank lines, found %d",
+                    yield (0, "E301 expected {} blank lines, found %d",
                         method_lines, blank_before)
         elif blank_before != top_level_lines:
-            yield (0, "E302 expected %s blank lines, found %d",
+            yield (0, "E302 expected {} blank lines, found {}",
                 top_level_lines, blank_before)
     elif (logical_line and
             not indent_level and
             blank_before != top_level_lines and
             previous_unindented_logical_line.startswith(('def ', 'class '))
           ):
-        yield (0, "E305 expected %s blank lines after " \
-            "class or function definition, found %d",
+        yield (0, "E305 expected {} blank lines after " \
+            "class or function definition, found {}",
                 top_level_lines, blank_before)
 
 
@@ -499,7 +478,7 @@
             yield found + 1, "E201 whitespace after '%s'", char
         elif line[found - 1] != ',':
             code = ('E202' if char in '}])' else 'E203')  # if char in ',;:'
-            yield found, "%s whitespace before '%s'" % (code, char), char
+            yield found, f"{code} whitespace before '{char}'", char
 
 
 @register_check
@@ -527,21 +506,26 @@
 
 
 @register_check
-def missing_whitespace_after_import_keyword(logical_line):
-    r"""Multiple imports in form from x import (a, b, c) should have
-    space between import statement and parenthesised name list.
+def missing_whitespace_after_keyword(logical_line, tokens):
+    r"""Keywords should be followed by whitespace.
 
     Okay: from foo import (bar, baz)
     E275: from foo import(bar, baz)
     E275: from importable.module import(bar, baz)
+    E275: if(foo): bar
     """
-    line = logical_line
-    indicator = ' import('
-    if line.startswith('from '):
-        found = line.find(indicator)
-        if -1 < found:
-            pos = found + len(indicator) - 1
-            yield pos, "E275 missing whitespace after keyword"
+    for tok0, tok1 in zip(tokens, tokens[1:]):
+        # This must exclude the True/False/None singletons, which can
+        # appear e.g. as "if x is None:", and async/await, which were
+        # valid identifier names in old Python versions.
+        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'):
+            yield tok0.end, "E275 missing whitespace after keyword"
 
 
 @register_check
@@ -760,7 +744,7 @@
             indent[depth] = start[1]
             indent_chances[start[1]] = True
             if verbose >= 4:
-                print("bracket depth %s indent to %s" % (depth, start[1]))
+                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')):
@@ -1089,21 +1073,24 @@
 
 @register_check
 def whitespace_before_comment(logical_line, tokens):
-    r"""Separate inline comments by at least two spaces.
+    """Separate inline comments by at least two spaces.
 
     An inline comment is a comment on the same line as a statement.
     Inline comments should be separated by at least two spaces from the
     statement. They should start with a # and a single space.
 
-    Each line of a block comment starts with a # and a single space
-    (unless it is indented text inside the comment).
+    Each line of a block comment starts with a # and one or multiple
+    spaces as there can be indented text inside the comment.
 
     Okay: x = x + 1  # Increment x
     Okay: x = x + 1    # Increment x
-    Okay: # Block comment
+    Okay: # Block comments:
+    Okay: #  - Block comment list
+    Okay: # \xa0- Block comment list
     E261: x = x + 1 # Increment x
     E262: x = x + 1  #Increment x
     E262: x = x + 1  #  Increment x
+    E262: x = x + 1  # \xa0Increment x
     E265: #Block comment
     E266: ### Block comment
     """
@@ -1253,7 +1240,7 @@
             lambda_kw = LAMBDA_REGEX.search(line, 0, found)
             if lambda_kw:
                 before = line[:lambda_kw.start()].rstrip()
-                if before[-1:] == '=' and isidentifier(before[:-1].strip()):
+                if before[-1:] == '=' and before[:-1].strip().isidentifier():
                     yield 0, ("E731 do not assign a lambda expression, use a "
                               "def")
                 break
@@ -1313,20 +1300,19 @@
                 parens -= 1
 
 
+# The % character is strictly speaking a binary operator, but the
+# common usage seems to be to put it next to the format parameters,
+# after a line break.
 _SYMBOLIC_OPS = frozenset("()[]{},:.;@=%~") | frozenset(("...",))
 
 
 def _is_binary_operator(token_type, text):
-    is_op_token = token_type == tokenize.OP
-    is_conjunction = text in ['and', 'or']
-    # NOTE(sigmavirus24): Previously the not_a_symbol check was executed
-    # conditionally. Since it is now *always* executed, text may be
-    # None. In that case we get a TypeError for `text not in str`.
-    not_a_symbol = text and text not in _SYMBOLIC_OPS
-    # The % character is strictly speaking a binary operator, but the
-    # common usage seems to be to put it next to the format parameters,
-    # after a line break.
-    return ((is_op_token or is_conjunction) and not_a_symbol)
+    return (
+        token_type == tokenize.OP or
+        text in {'and', 'or'}
+    ) and (
+        text not in _SYMBOLIC_OPS
+    )
 
 
 def _break_around_binary_operators(tokens):
@@ -1498,7 +1484,7 @@
     match = COMPARE_TYPE_REGEX.search(logical_line)
     if match and not noqa:
         inst = match.group(1)
-        if inst and isidentifier(inst) and inst not in SINGLETONS:
+        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()'"
 
@@ -1816,12 +1802,6 @@
             if prev_token is None or prev_token in SKIP_TOKENS:
                 lines = line.splitlines()
                 for line_num, physical_line in enumerate(lines):
-                    if hasattr(physical_line, 'decode'):  # Python 2
-                        # The line could contain multi-byte characters
-                        try:
-                            physical_line = physical_line.decode('utf-8')
-                        except UnicodeError:
-                            pass
                     if start[0] + line_num == 1 and line.startswith('#!'):
                         return
                     length = len(physical_line)
@@ -1847,30 +1827,19 @@
 ########################################################################
 
 
-if sys.version_info < (3,):
-    # Python 2: implicit encoding.
-    def readlines(filename):
-        """Read the source code."""
-        with open(filename, 'rU') as f:
+def readlines(filename):
+    """Read the source code."""
+    try:
+        with tokenize.open(filename) as f:
             return f.readlines()
-    isidentifier = re.compile(r'[a-zA-Z_]\w*$').match
-    stdin_get_value = sys.stdin.read
-else:
-    # Python 3
-    def readlines(filename):
-        """Read the source code."""
-        try:
-            with tokenize.open(filename) as f:
-                return f.readlines()
-        except (LookupError, SyntaxError, UnicodeError):
-            # Fall back if file encoding is improperly declared
-            with open(filename, encoding='latin-1') as f:
-                return f.readlines()
-    isidentifier = str.isidentifier
-
-    def stdin_get_value():
-        """Read the value from stdin."""
-        return TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
+    except (LookupError, SyntaxError, UnicodeError):
+        # Fall back if file encoding is improperly declared
+        with open(filename, encoding='latin-1') as f:
+            return f.readlines()
+
+def stdin_get_value():
+    """Read the value from stdin."""
+    return TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
 
 noqa = lru_cache(512)(re.compile(r'# no(?:qa|pep8)\b', re.I).search)
 
@@ -1936,7 +1905,7 @@
             continue
         if line[:3] == '@@ ':
             hunk_match = HUNK_REGEX.match(line)
-            (row, nrows) = [int(g or '1') for g in hunk_match.groups()]
+            (row, nrows) = (int(g or '1') for g in hunk_match.groups())
             rv[path].update(range(row, row + nrows))
         elif line[:3] == '+++':
             path = line[4:].split('\t', 1)[0]
@@ -1997,7 +1966,7 @@
 ########################################################################
 
 
-class Checker(object):
+class Checker:
     """Load a Python source file, tokenize it, check coding style."""
 
     def __init__(self, filename=None, lines=None,
@@ -2031,7 +2000,7 @@
                 self.lines = readlines(filename)
             except OSError:
                 (exc_type, exc) = sys.exc_info()[:2]
-                self._io_error = '%s: %s' % (exc_type.__name__, exc)
+                self._io_error = f'{exc_type.__name__}: {exc}'
                 self.lines = []
         else:
             self.lines = lines
@@ -2260,7 +2229,7 @@
             token_type, text = token[0:2]
             if self.verbose >= 3:
                 if token[2][0] == token[3][0]:
-                    pos = '[%s:%s]' % (token[2][1] or '', token[3][1])
+                    pos = '[{}:{}]'.format(token[2][1] or '', token[3][1])
                 else:
                     pos = 'l.%s' % token[3][0]
                 print('l.%s\t%s\t%s\t%r' %
@@ -2287,7 +2256,7 @@
         return self.report.get_file_results()
 
 
-class BaseReport(object):
+class BaseReport:
     """Collect the results of the checks."""
 
     print_filename = False
@@ -2388,7 +2357,7 @@
 
     def print_benchmark(self):
         """Print benchmark numbers."""
-        print('%-7.2f %s' % (self.elapsed, 'seconds elapsed'))
+        print('{:<7.2f} {}'.format(self.elapsed, 'seconds elapsed'))
         if self.elapsed:
             for key in self._benchmark_keys:
                 print('%-7d %s per second (%d total)' %
@@ -2421,8 +2390,7 @@
 
     def error(self, line_number, offset, text, check):
         """Report an error, according to options."""
-        code = super().error(line_number, offset,
-                                                 text, check)
+        code = super().error(line_number, offset, text, check)
         if code and (self.counters[code] == 1 or self._repeat):
             self._deferred_print.append(
                 (line_number, offset, code, text[5:], check.__doc__))
@@ -2479,7 +2447,7 @@
         return super().error(line_number, offset, text, check)
 
 
-class StyleGuide(object):
+class StyleGuide:
     """Initialize a PEP-8 instance with few options."""
 
     def __init__(self, *args, **kwargs):
@@ -2572,8 +2540,10 @@
                     dirs.remove(subdir)
             for filename in sorted(files):
                 # contain a pattern that matches?
-                if ((filename_match(filename, filepatterns) and
-                     not self.excluded(filename, root))):
+                if (
+                    filename_match(filename, filepatterns) and
+                    not self.excluded(filename, root)
+                ):
                     runner(os.path.join(root, filename))
 
     def excluded(self, filename, parent=None):
@@ -2743,8 +2713,8 @@
                 print("  unknown option '%s' ignored" % opt)
                 continue
             if options.verbose > 1:
-                print("  %s = %s" % (opt,
-                                     config.get(pycodestyle_section, opt)))
+                print("  {} = {}".format(opt,
+                                         config.get(pycodestyle_section, opt)))
             normalized_opt = opt.replace('-', '_')
             opt_type = option_list[normalized_opt]
             if opt_type in ('int', 'count'):

eric ide

mercurial