summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJulien Palard <julien@palard.fr>2017-05-06 09:57:02 +0200
committerJulien Palard <julien@palard.fr>2017-05-09 19:44:42 +0200
commit7b98ff3a9471c6b111f477ea06e8fc207568172a (patch)
tree23cbdb9cd290ecbedef098a79768d26f09c64b95
parentd5cc5f6430a5e033289de657152399893b1a83ef (diff)
downloadpep8-7b98ff3a9471c6b111f477ea06e8fc207568172a.tar.gz
Avoid relying on inspect to list functions.
This allow to run python3 -m cProfile ./pycodestyle.py …. Otherwise, as cProfile looks to wrap every functions (in a way I did not studied in depth), the inspection of test function found no function, and no test were run while running under cProfile, meaning that: $ time python3 ./pycodestyle.py coefficients-148K.py [loads and loads of errors properly reported] real 0m4.712s user 0m4.684s sys 0m0.024s $ time python3 -m cProfile ./pycodestyle.py /home/mdk/Downloads/pystyle/stats/git-clones/PmagPy/PmagPy/coefficients-148K.py [no error reported as no check were found by inspection] real 0m0.447s user 0m0.436s sys 0m0.008s With this patch: $ time python3 -m cProfile ./pycodestyle.py /home/mdk/Downloads/pystyle/stats/git-clones/PmagPy/PmagPy/coefficients-148K.py [loads and loads of errors properly reported] real 0m4.889s user 0m4.852s sys 0m0.032s
-rwxr-xr-xpycodestyle.py109
1 files changed, 64 insertions, 45 deletions
diff --git a/pycodestyle.py b/pycodestyle.py
index 556467b..2e03301 100755
--- a/pycodestyle.py
+++ b/pycodestyle.py
@@ -141,11 +141,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 +197,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 +209,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 +231,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 +248,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 +287,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 +350,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 +383,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 +407,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 +425,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 +452,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 +484,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 +684,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 +717,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 +741,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 +834,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 +853,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 +904,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 +946,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 +966,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 +1023,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 +1084,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 +1124,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 +1174,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 +1209,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 +1231,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,6 +1255,7 @@ 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 when possible.
@@ -1214,6 +1272,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 +1325,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 +1337,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 +1351,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 +1365,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.
@@ -1471,50 +1534,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."""