Sat, 11 Feb 2017 18:19:56 +0100
Merged with changes of Tobias.
--- a/Plugins/CheckerPlugins/CodeStyleChecker/pycodestyle.py Sat Feb 11 17:50:07 2017 +0100 +++ b/Plugins/CheckerPlugins/CodeStyleChecker/pycodestyle.py Sat Feb 11 18:19:56 2017 +0100 @@ -79,7 +79,7 @@ except ImportError: from ConfigParser import RawConfigParser # __IGNORE_WARNING__ -__version__ = '2.2.0-eric' +__version__ = '2.3.1-eric' DEFAULT_EXCLUDE = '.svn,CVS,.bzr,.hg,.git,__pycache__,.tox' DEFAULT_IGNORE = 'E121,E123,E126,E226,E24,E704,W503' @@ -134,6 +134,20 @@ 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)') +STARTSWITH_TOP_LEVEL_REGEX = re.compile(r'^(async\s+def\s+|def\s+|class\s+|@)') +STARTSWITH_INDENT_STATEMENT_REGEX = re.compile( + r'^\s*({0})'.format('|'.join(s.replace(' ', '\s+') for s in ( + 'def', 'async def', + 'for', 'async for', + 'if', 'elif', 'else', + 'try', 'except', 'finally', + 'with', 'async with', + 'class', + 'while', + ))) +) +DUNDER_REGEX = re.compile(r'^__([^\s]+)__ = ') # Work around Python < 2.6 behaviour, which does not generate NL after # a comment which is on a line by itself. @@ -278,6 +292,7 @@ E303: def a():\n\n\n\n pass E304: @decorator\n\ndef a():\n pass E305: def a():\n pass\na() + E306: def a():\n def b():\n pass\n def c():\n pass """ if line_number < 3 and not previous_logical: return # Don't expect blank lines before the first line @@ -286,7 +301,7 @@ yield 0, "E304 blank lines found after function decorator" elif blank_lines > 2 or (indent_level and blank_lines == 2): yield 0, "E303 too many blank lines (%d)", blank_lines - elif logical_line.startswith(('def ', 'async def ', 'class ', '@')): + elif STARTSWITH_TOP_LEVEL_REGEX.match(logical_line): if indent_level: if not (blank_before or previous_indent_level < indent_level or DOCSTRING_REGEX.match(previous_logical)): @@ -827,7 +842,7 @@ no_space = False prev_end = None annotated_func_arg = False - in_def = logical_line.startswith(('def', 'async def')) + in_def = bool(STARTSWITH_DEF_REGEX.match(logical_line)) message = "E251 unexpected spaces around keyword / parameter equals" for token_type, text, start, end, line in tokens: if token_type == tokenize.NL: @@ -956,6 +971,8 @@ if line.startswith('import ') or line.startswith('from '): if checker_state.get('seen_non_imports', False): yield 0, "E402 module level import not at top of file" + elif re.match(DUNDER_REGEX, line): + return elif any(line.startswith(kw) for kw in allowed_try_keywords): # Allow try, except, else, finally keywords intermixed with imports in # order to support conditional importing @@ -996,7 +1013,6 @@ E702: do_one(); do_two(); do_three() E703: do_four(); # useless semicolon E704: def f(x): return 2*x - E705: async def f(x): return 2*x E731: f = lambda x: 2*x """ line = logical_line @@ -1016,11 +1032,9 @@ yield 0, ("E731 do not assign a lambda expression, use a " "def") break - if line.startswith('def '): + if STARTSWITH_DEF_REGEX.match(line): yield 0, "E704 multiple statements on one line (def)" - elif line.startswith('async def '): - yield 0, "E705 multiple statements on one line (async def)" - else: + elif STARTSWITH_INDENT_STATEMENT_REGEX.match(line): yield found, "E701 multiple statements on one line (colon)" prev_found = found found = line.find(':', found + 1)
--- a/Plugins/CheckerPlugins/CodeStyleChecker/translations.py Sat Feb 11 17:50:07 2017 +0100 +++ b/Plugins/CheckerPlugins/CodeStyleChecker/translations.py Sat Feb 11 18:19:56 2017 +0100 @@ -219,9 +219,6 @@ "E704": QCoreApplication.translate( "pycodestyle", "multiple statements on one line (def)"), - "E705": QCoreApplication.translate( - "pycodestyle", - "multiple statements on one line (async def)"), "E711": QCoreApplication.translate( "pycodestyle", "comparison to {0} should be {1}"),
--- a/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/__init__.py Sat Feb 11 17:50:07 2017 +0100 +++ b/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/__init__.py Sat Feb 11 18:19:56 2017 +0100 @@ -32,6 +32,19 @@ """ """ Changes +1.5.0 (2017-01-09) + - Enable support for PEP 526 annotated assignments + +1.4.0 (2016-12-30): + - Change formatting of ImportStarMessage to be consistent with other errors + - Support PEP 498 "f-strings" + +1.3.0 (2016-09-01): + - Fix PyPy2 Windows IntegrationTests + - Check for duplicate dictionary keys + - Fix TestMain tests on Windows + - Fix "continue" and "break" checks ignoring py3.5's "async for" loop + 1.2.3 (2016-05-12): - Fix TypeError when processing relative imports
--- a/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/checker.py Sat Feb 11 17:50:07 2017 +0100 +++ b/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/checker.py Sat Feb 11 18:19:56 2017 +0100 @@ -311,7 +311,7 @@ class StarImportation(Importation): - """A binding created by an 'from x import *' statement.""" + """A binding created by a 'from x import *' statement.""" def __init__(self, name, source): super(StarImportation, self).__init__('*', source) @@ -806,7 +806,7 @@ return if on_conditional_branch(): - # We can not predict if this conditional branch is going to + # We cannot predict if this conditional branch is going to # be executed. return @@ -944,7 +944,7 @@ MATMULT = ignore # additional node types - COMPREHENSION = KEYWORD = FORMATTEDVALUE = handleChildren + COMPREHENSION = KEYWORD = FORMATTEDVALUE = JOINEDSTR = handleChildren def DICT(self, node): # Complain if there are duplicate keys with different values @@ -1328,7 +1328,7 @@ self.handleNodeStore(node) self.handleChildren(node) if not is_name_previously_defined: - # See discussion on https://github.com/pyflakes/pyflakes/pull/59. + # See discussion on https://github.com/PyCQA/pyflakes/pull/59 # We're removing the local name since it's being unbound # after leaving the except: block and it's always unbound @@ -1343,5 +1343,24 @@ except KeyError: pass + def ANNASSIGN(self, node): + """ + Annotated assignments don't have annotations evaluated on function + scope, hence the custom implementation. + + See: PEP 526. + """ + if node.value: + # Only bind the *targets* if the assignment has a value. + # Otherwise it's not really ast.Store and shouldn't silence + # UndefinedLocal warnings. + self.handleNode(node.target, node) + if not isinstance(self.scope, FunctionScope): + self.handleNode(node.annotation, node) + if node.value: + # If the assignment has value, handle the *value* now. + self.handleNode(node.value, node) + + # # eflag: noqa = M702
--- a/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/messages.py Sat Feb 11 17:50:07 2017 +0100 +++ b/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/messages.py Sat Feb 11 18:19:56 2017 +0100 @@ -173,7 +173,7 @@ Class defining the "Import Star Usage" message. """ message_id = 'F17' - message = "%s may be undefined, or defined from star imports: %s" + message = "%r may be undefined, or defined from star imports: %s" def __init__(self, filename, loc, name, from_list): """
--- a/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/translations.py Sat Feb 11 17:50:07 2017 +0100 +++ b/Plugins/CheckerPlugins/SyntaxChecker/pyflakes/translations.py Sat Feb 11 18:19:56 2017 +0100 @@ -65,7 +65,7 @@ "'from {0} import *' only allowed at module level"), 'F17': QCoreApplication.translate( 'pyFlakes', - "{0} may be undefined, or defined from star imports: {1}"), + "{0!r} may be undefined, or defined from star imports: {1}"), 'F18': QCoreApplication.translate( 'pyFlakes', "Dictionary key {0!r} repeated with different values"),