Plugins/CheckerPlugins/CodeStyleChecker/pycodestyle.py

changeset 5509
d4c4763b46ee
parent 5435
44a6fc2828bc
child 6048
82ad8ec9548c
--- a/Plugins/CheckerPlugins/CodeStyleChecker/pycodestyle.py	Wed Feb 08 20:17:39 2017 +0100
+++ b/Plugins/CheckerPlugins/CodeStyleChecker/pycodestyle.py	Wed Feb 08 21:36:29 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)

eric ide

mercurial