summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEddie Antonio Santos <easantos@ualberta.ca>2017-06-07 10:10:09 -0600
committerGitHub <noreply@github.com>2017-06-07 10:10:09 -0600
commita46c7a6c31773950f5e015a7eb5883f44a8e11de (patch)
tree3972ab004ceb3ca35390ef8ae2bfe795f4eee5fa
parentd87a44367c5542ab8052c212e6d51f1532086dd1 (diff)
parent454e035fd969ee5d6da76fcc169ee028933f391e (diff)
downloadpep8-a46c7a6c31773950f5e015a7eb5883f44a8e11de.tar.gz
Merge branch 'master' into fix-variable-annotations
-rw-r--r--.gitattributes1
-rwxr-xr-xpycodestyle.py139
-rw-r--r--setup.cfg2
-rw-r--r--testsuite/E50.py5
4 files changed, 93 insertions, 54 deletions
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..0aadd30
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+testsuite/E90.py -text
diff --git a/pycodestyle.py b/pycodestyle.py
index 03cdd62..5b7a39c 100755
--- a/pycodestyle.py
+++ b/pycodestyle.py
@@ -56,6 +56,17 @@ import sys
import time
import tokenize
import warnings
+import bisect
+
+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 optparse import OptionParser
@@ -124,7 +135,7 @@ 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(' ', '\s+') for s in (
+ r'^\s*({0})\b'.format('|'.join(s.replace(' ', r'\s+') for s in (
'def', 'async def',
'for', 'async for',
'if', 'elif', 'else',
@@ -141,11 +152,43 @@ DUNDER_REGEX = re.compile(r'^__([^\s]+)__ = ')
COMMENT_WITH_NL = tokenize.generate_tokens(['#\n'].pop).send(None)[1] == '#\n'
+_checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
+
+
+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]
+
+
+def register_check(check, codes=None):
+ """Register a new check object."""
+ def _add_check(check, kind, codes, args):
+ if check in _checks[kind]:
+ _checks[kind][check][0].extend(codes or [])
+ else:
+ _checks[kind][check] = (codes or [''], args)
+ if inspect.isfunction(check):
+ args = _get_parameters(check)
+ if args and args[0] in ('physical_line', 'logical_line'):
+ if codes is None:
+ codes = ERRORCODE_REGEX.findall(check.__doc__ or '')
+ _add_check(check, args[0], codes, args)
+ elif inspect.isclass(check):
+ if _get_parameters(check.__init__)[:2] == ['self', 'tree']:
+ _add_check(check, 'tree', codes, None)
+ return check
+
+
##############################################################################
# Plugins (check functions) for physical lines
##############################################################################
-
+@register_check
def tabs_or_spaces(physical_line, indent_char):
r"""Never mix tabs and spaces.
@@ -165,6 +208,7 @@ def tabs_or_spaces(physical_line, indent_char):
return offset, "E101 indentation contains mixed spaces and tabs"
+@register_check
def tabs_obsolete(physical_line):
r"""For new projects, spaces-only are strongly recommended over tabs.
@@ -176,6 +220,7 @@ def tabs_obsolete(physical_line):
return indent.index('\t'), "W191 indentation contains tabs"
+@register_check
def trailing_whitespace(physical_line):
r"""Trailing whitespace is superfluous.
@@ -197,6 +242,7 @@ def trailing_whitespace(physical_line):
return 0, "W293 blank line contains whitespace"
+@register_check
def trailing_blank_lines(physical_line, lines, line_number, total_lines):
r"""Trailing blank lines are superfluous.
@@ -213,6 +259,7 @@ def trailing_blank_lines(physical_line, lines, line_number, total_lines):
return len(physical_line), "W292 no newline at end of file"
+@register_check
def maximum_line_length(physical_line, max_line_length, multiline, noqa):
r"""Limit all lines to a maximum of 79 characters.
@@ -251,6 +298,7 @@ def maximum_line_length(physical_line, max_line_length, multiline, noqa):
##############################################################################
+@register_check
def blank_lines(logical_line, blank_lines, indent_level, line_number,
blank_before, previous_logical,
previous_unindented_logical_line, previous_indent_level,
@@ -313,6 +361,7 @@ def blank_lines(logical_line, blank_lines, indent_level, line_number,
"class or function definition, found %d" % blank_before
+@register_check
def extraneous_whitespace(logical_line):
r"""Avoid extraneous whitespace.
@@ -345,6 +394,7 @@ def extraneous_whitespace(logical_line):
yield found, "%s whitespace before '%s'" % (code, char)
+@register_check
def whitespace_around_keywords(logical_line):
r"""Avoid extraneous whitespace around keywords.
@@ -368,6 +418,7 @@ def whitespace_around_keywords(logical_line):
yield match.start(2), "E271 multiple spaces after keyword"
+@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.
@@ -385,6 +436,7 @@ def missing_whitespace_after_import_keyword(logical_line):
yield pos, "E275 missing whitespace after keyword"
+@register_check
def missing_whitespace(logical_line):
r"""Each comma, semicolon or colon should be followed by whitespace.
@@ -411,6 +463,7 @@ def missing_whitespace(logical_line):
yield index, "E231 missing whitespace after '%s'" % char
+@register_check
def indentation(logical_line, previous_logical, indent_char,
indent_level, previous_indent_level):
r"""Use 4 spaces per indentation level.
@@ -442,6 +495,7 @@ def indentation(logical_line, previous_logical, indent_char,
yield 0, tmpl % (3 + c, "unexpected indentation")
+@register_check
def continued_indentation(logical_line, tokens, indent_level, hang_closing,
indent_char, noqa, verbose):
r"""Continuation lines indentation.
@@ -641,6 +695,7 @@ def continued_indentation(logical_line, tokens, indent_level, hang_closing,
yield pos, "%s with same indent as next logical line" % code
+@register_check
def whitespace_before_parameters(logical_line, tokens):
r"""Avoid extraneous whitespace.
@@ -673,6 +728,7 @@ def whitespace_before_parameters(logical_line, tokens):
prev_end = end
+@register_check
def whitespace_around_operator(logical_line):
r"""Avoid extraneous whitespace around an operator.
@@ -696,6 +752,7 @@ def whitespace_around_operator(logical_line):
yield match.start(2), "E222 multiple spaces after operator"
+@register_check
def missing_whitespace_around_operator(logical_line, tokens):
r"""Surround operators with a single space on either side.
@@ -788,6 +845,7 @@ def missing_whitespace_around_operator(logical_line, tokens):
prev_end = end
+@register_check
def whitespace_around_comma(logical_line):
r"""Avoid extraneous whitespace after a comma or a colon.
@@ -806,6 +864,7 @@ def whitespace_around_comma(logical_line):
yield found, "E241 multiple spaces after '%s'" % m.group()[0]
+@register_check
def whitespace_around_named_parameter_equals(logical_line, tokens):
r"""Don't use spaces around the '=' sign in function arguments.
@@ -856,6 +915,7 @@ def whitespace_around_named_parameter_equals(logical_line, tokens):
prev_end = end
+@register_check
def whitespace_before_comment(logical_line, tokens):
r"""Separate inline comments by at least two spaces.
@@ -897,6 +957,7 @@ def whitespace_before_comment(logical_line, tokens):
prev_end = end
+@register_check
def imports_on_separate_lines(logical_line):
r"""Place imports on separate lines.
@@ -916,6 +977,7 @@ def imports_on_separate_lines(logical_line):
yield found, "E401 multiple imports on one line"
+@register_check
def module_imports_on_top_of_file(
logical_line, indent_level, checker_state, noqa):
r"""Place imports at the top of the file.
@@ -972,6 +1034,7 @@ def module_imports_on_top_of_file(
checker_state['seen_non_imports'] = True
+@register_check
def compound_statements(logical_line):
r"""Compound statements (on the same line) are generally discouraged.
@@ -1032,6 +1095,7 @@ def compound_statements(logical_line):
found = line.find(';', found + 1)
+@register_check
def explicit_line_join(logical_line, tokens):
r"""Avoid explicit line join between brackets.
@@ -1071,6 +1135,7 @@ def explicit_line_join(logical_line, tokens):
parens -= 1
+@register_check
def break_around_binary_operator(logical_line, tokens):
r"""
Avoid breaks before binary operators.
@@ -1120,6 +1185,7 @@ def break_around_binary_operator(logical_line, tokens):
previous_text = text
+@register_check
def comparison_to_singleton(logical_line, noqa):
r"""Comparison to singletons should use "is" or "is not".
@@ -1154,6 +1220,7 @@ def comparison_to_singleton(logical_line, noqa):
(code, singleton, msg))
+@register_check
def comparison_negative(logical_line):
r"""Negative comparison should be done using "not in" and "is not".
@@ -1175,6 +1242,7 @@ def comparison_negative(logical_line):
yield pos, "E714 test for object identity should be 'is not'"
+@register_check
def comparison_type(logical_line, noqa):
r"""Object type comparisons should always use isinstance().
@@ -1198,8 +1266,9 @@ def comparison_type(logical_line, noqa):
yield match.start(), "E721 do not compare types, use 'isinstance()'"
+@register_check
def bare_except(logical_line, noqa):
- r"""When catching exceptions, mention specific exceptions whenever possible.
+ r"""When catching exceptions, mention specific exceptions when possible.
Okay: except Exception:
Okay: except BaseException:
@@ -1214,6 +1283,7 @@ def bare_except(logical_line, noqa):
yield match.start(), "E722 do not use bare except'"
+@register_check
def ambiguous_identifier(logical_line, tokens):
r"""Never use the characters 'l', 'O', or 'I' as variable names.
@@ -1266,6 +1336,7 @@ def ambiguous_identifier(logical_line, tokens):
prev_start = start
+@register_check
def python_3000_has_key(logical_line, noqa):
r"""The {}.has_key() method is removed in Python 3: use the 'in' operator.
@@ -1277,6 +1348,7 @@ def python_3000_has_key(logical_line, 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')".
@@ -1290,6 +1362,7 @@ def python_3000_raise_comma(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 <>.
@@ -1303,6 +1376,7 @@ def python_3000_not_equal(logical_line):
yield pos, "W603 '<>' is deprecated, use '!='"
+@register_check
def python_3000_backticks(logical_line):
r"""Use repr() instead of backticks in Python 3.
@@ -1346,7 +1420,7 @@ else:
"""Read the value from stdin."""
return TextIOWrapper(sys.stdin.buffer, errors='ignore').read()
-noqa = re.compile(r'# no(?:qa|pep8)\b', re.I).search
+noqa = lru_cache(512)(re.compile(r'# no(?:qa|pep8)\b', re.I).search)
def expand_indent(line):
@@ -1471,50 +1545,6 @@ if COMMENT_WITH_NL:
##############################################################################
-_checks = {'physical_line': {}, 'logical_line': {}, 'tree': {}}
-
-
-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]
-
-
-def register_check(check, codes=None):
- """Register a new check object."""
- def _add_check(check, kind, codes, args):
- if check in _checks[kind]:
- _checks[kind][check][0].extend(codes or [])
- else:
- _checks[kind][check] = (codes or [''], args)
- if inspect.isfunction(check):
- args = _get_parameters(check)
- if args and args[0] in ('physical_line', 'logical_line'):
- if codes is None:
- codes = ERRORCODE_REGEX.findall(check.__doc__ or '')
- _add_check(check, args[0], codes, args)
- elif inspect.isclass(check):
- if _get_parameters(check.__init__)[:2] == ['self', 'tree']:
- _add_check(check, 'tree', codes, None)
-
-
-def init_checks_registry():
- """Register all globally visible functions.
-
- The first argument name is either 'physical_line' or 'logical_line'.
- """
- mod = inspect.getmodule(register_check)
- for (name, function) in inspect.getmembers(mod, inspect.isfunction):
- register_check(function)
-
-
-init_checks_registry()
-
-
class Checker(object):
"""Load a Python source file, tokenize it, check coding style."""
@@ -1645,10 +1675,10 @@ class Checker(object):
"""Build a line from tokens and run all logical checks on it."""
self.report.increment_logical_line()
mapping = self.build_tokens_line()
-
if not mapping:
return
+ mapping_offsets = [offset for offset, _ in mapping]
(start_row, start_col) = mapping[0][1]
start_line = self.lines[start_row - 1]
self.indent_level = expand_indent(start_line[:start_col])
@@ -1662,9 +1692,10 @@ class Checker(object):
self.init_checker_state(name, argument_names)
for offset, text in self.run_check(check, argument_names) or ():
if not isinstance(offset, tuple):
- for token_offset, pos in mapping:
- if offset <= token_offset:
- break
+ # As mappings are ordered, bisecting is a fast way
+ # to find a given offset in them.
+ token_offset, pos = mapping[bisect.bisect_left(
+ mapping_offsets, offset)]
offset = (pos[0], pos[1] + offset - token_offset)
self.report_error(offset[0], offset[1], text, check)
if self.logical_line:
@@ -1727,7 +1758,9 @@ class Checker(object):
return
self.multiline = True
self.line_number = token[2][0]
- for line in token[1].split('\n')[:-1]:
+ _, 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 += 1
self.multiline = False
diff --git a/setup.cfg b/setup.cfg
index 803bc10..fcc079a 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -1,4 +1,4 @@
-[wheel]
+[bdist_wheel]
universal = 1
[pycodestyle]
diff --git a/testsuite/E50.py b/testsuite/E50.py
index f60f389..189f416 100644
--- a/testsuite/E50.py
+++ b/testsuite/E50.py
@@ -82,6 +82,11 @@ that I'm calling:
#: E501
"""
longnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaceslongnospaces"""
+#: E501
+# Regression test for #622
+def foo():
+ """Lorem ipsum dolor sit amet, consectetur adipiscing elit. Duis pulvinar vitae
+ """
#: Okay
"""
This