From d220a65222c68ab5a13d0bb333f12ba8912a3eac Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 8 Feb 2013 17:35:56 -0500 Subject: [PATCH 1/4] Transition to pyflakes 0.6.1 That was less painful than I thought it would be. --- README.rst | 28 +++++++++++++--------------- flake8/main.py | 35 ++++++++++++++++------------------- flake8/util.py | 45 ++++++++++++++++++++++++++++++++++++++++----- setup.py | 2 +- 4 files changed, 70 insertions(+), 40 deletions(-) diff --git a/README.rst b/README.rst index 2326259..d52b6de 100644 --- a/README.rst +++ b/README.rst @@ -210,17 +210,17 @@ pep8: flakey: -- YW402: imported but unused -- YW403: import from line shadowed by loop variable -- YW404: 'from import ``*``' used; unable to detect undefined names -- YW405: future import(s) after other statements -- YW801: redefinition of unused from line -- YW802: undefined name -- YW803: undefined name in __all__ -- YW804: local variable (defined in enclosing scope on line ) referenced before assignment -- YW805: duplicate argument in function definition -- YW806: redefinition of function from line -- YW806: local variable is assigned to but never used +- W402: imported but unused +- W403: import from line shadowed by loop variable +- W404: 'from import ``*``' used; unable to detect undefined names +- W405: future import(s) after other statements +- W801: redefinition of unused from line +- W802: undefined name +- W803: undefined name in __all__ +- W804: local variable (defined in enclosing scope on line ) referenced before assignment +- W805: duplicate argument in function definition +- W806: redefinition of function from line +- W806: local variable is assigned to but never used McCabe: @@ -232,13 +232,11 @@ CHANGES 2.0.0 - 2013-01-xx ------------------ -- Fixes #13: pep8 and flakey are now external dependencies +- Fixes #13: pep8 and pyflakes are now external dependencies - Split run.py into main.py and hooks.py for better logic - Expose our parser for our users - New feature: Install git and hg hooks automagically -- By relying on flakey, we also fixed #45 and #35 -- Changed the way flakey errors are printed. Both the old and new versions - will be ignored when specified at the command-line though. +- By relying on pyflakes (0.6.1), we also fixed #45 and #35 1.7.0 - 2012-12-21 ------------------ diff --git a/flake8/main.py b/flake8/main.py index 0bba669..8eef20b 100644 --- a/flake8/main.py +++ b/flake8/main.py @@ -1,11 +1,12 @@ import os import sys import pep8 -import flakey +import pyflakes.api +import pyflakes.checker import select from flake8 import mccabe from flake8.util import (_initpep8, skip_file, get_parser, read_config, - merge_opts) + merge_opts, Flake8Reporter) pep8style = None @@ -49,8 +50,11 @@ def main(): builtins = set(opts.builtins.split(',')) if builtins: - orig_builtins = set(flakey.checker._MAGIC_GLOBALS) - flakey.checker._MAGIC_GLOBALS = orig_builtins | builtins + orig_builtins = set(pyflakes.checker._MAGIC_GLOBALS) + pyflakes.checker._MAGIC_GLOBALS = orig_builtins | builtins + + # This is needed so we can ignore some items + pyflakes_reporter = Flake8Reporter(opts.ignore) if pep8style.paths and pep8style.options.filename is not None: for path in _get_python_files(pep8style.paths): @@ -59,10 +63,12 @@ def main(): stdin = read_stdin() warnings += check_code(stdin, opts.ignore, complexity) else: - warnings += check_file(path, opts.ignore, complexity) + warnings += check_file(path, opts.ignore, complexity, + pyflakes_reporter) else: stdin = read_stdin() - warnings += check_code(stdin, opts.ignore, complexity) + warnings += check_code(stdin, opts.ignore, complexity, + pyflakes_reporter) if opts.exit_zero: raise SystemExit(0) @@ -70,27 +76,18 @@ def main(): raise SystemExit(warnings) -def _set_alt(warning): - for m in warning.messages: - m.error_code, m.alt_error_code = m.alt_error_code, m.error_code - - -def check_file(path, ignore=(), complexity=-1): +def check_file(path, ignore=(), complexity=-1, reporter=None): if pep8style.excluded(path): return 0 - warning = flakey.check_path(path) - _set_alt(warning) - warnings = flakey.print_messages(warning, ignore=ignore) + warnings = pyflakes.api.checkPath(path, reporter) warnings += pep8style.input_file(path) if complexity > -1: warnings += mccabe.get_module_complexity(path, complexity) return warnings -def check_code(code, ignore=(), complexity=-1): - warning = flakey.check(code, '') - _set_alt(warning) - warnings = flakey.print_messages(warning, ignore=ignore, code=code) +def check_code(code, ignore=(), complexity=-1, reporter=None): + warnings = pyflakes.api.check(code, '', reporter) warnings += pep8style.input_file('-', lines=code.split('\n')) if complexity > -1: warnings += mccabe.get_code_complexity(code, complexity) diff --git a/flake8/util.py b/flake8/util.py index 6228ad5..92e83cb 100644 --- a/flake8/util.py +++ b/flake8/util.py @@ -5,6 +5,8 @@ import sys from io import StringIO import optparse import pep8 +import pyflakes +from pyflakes import reporter, messages try: # Python 2 @@ -19,7 +21,6 @@ pep8style = None def get_parser(): """Create a custom OptionParser""" from flake8 import __version__ - import flakey parser = pep8.get_parser() def version(option, opt, value, parser): @@ -27,11 +28,11 @@ def get_parser(): parser.print_version() sys.exit(0) - parser.version = '{0} (pep8: {1}, flakey: {2})'.format( - __version__, pep8.__version__, flakey.__version__) + parser.version = '{0} (pep8: {1}, pyflakes: {2})'.format( + __version__, pep8.__version__, pyflakes.__version__) parser.remove_option('--version') parser.add_option('--builtins', default='', dest='builtins', - help="append builtin functions to flakey's " + help="append builtin functions to pyflakes' " "_MAGIC_BUILTINS") parser.add_option('--exit-zero', action='store_true', default=False, help='Exit with status 0 even if there are errors') @@ -48,7 +49,7 @@ def get_parser(): def read_config(opts, opt_parser): - configs = ('.flake8', '.pep8', 'tox.ini', 'setup.cfg') + configs = ('.flake8', '.pep8', 'tox.ini', 'setup.cfg',) parser = ConfigParser() files_found = parser.read(configs) if not (files_found and parser.has_section('flake8')): @@ -161,3 +162,37 @@ def _initpep8(config_file=True): pep8style.options.max_line_length = 79 pep8style.args = [] return pep8style + + +error_mapping = { + 'W402': messages.UnusedImport, + 'W403': messages.ImportShadowedByLoopVar, + 'W404': messages.ImportStarUsed, + 'W405': messages.LateFutureImport, + 'W801': (messages.RedefinedWhileUnused, + messages.RedefinedInListComp,), + 'W802': messages.UndefinedName, + 'W803': messages.UndefinedExport, + 'W804': (messages.UndefinedLocal, + messages.UnusedVariable,), + 'W805': messages.DuplicateArgument, + 'W806': messages.Redefined, +} + + +class Flake8Reporter(reporter.Reporter): + """Our own instance of a Reporter so that we can silence some messages.""" + #class_mapping = dict((k, c) for (c, v) in error_mapping.items() for k in + #v) + def __init__(self, ignore=None): + super(Flake8Reporter, self).__init__(sys.stdout, sys.stderr) + self.ignore = ignore or [] + + def flake(self, message): + classes = [error_mapping[i] for i in self.ignore if i in error_mapping] + + if (any(isinstance(message, c) for c in classes) or + skip_warning(message)): + return + + super(Flake8Reporter, self).flake(message) diff --git a/setup.py b/setup.py index 8321794..5dcee34 100644 --- a/setup.py +++ b/setup.py @@ -42,7 +42,7 @@ setup( url="http://bitbucket.org/tarek/flake8", packages=["flake8", "flake8.tests"], scripts=scripts, - install_requires=["flakey (==2.0)", "pep8 (==1.4.1)"], + install_requires=["pyflakes==0.6.1", "pep8"], long_description=README, classifiers=[ "Environment :: Console", From 8a325260227dc1791f804374ace3a71f2d0517e1 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 8 Feb 2013 17:53:08 -0500 Subject: [PATCH 2/4] Add error numbers to pyflakes messages --- flake8/util.py | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/flake8/util.py b/flake8/util.py index 92e83cb..3d16594 100644 --- a/flake8/util.py +++ b/flake8/util.py @@ -165,25 +165,24 @@ def _initpep8(config_file=True): error_mapping = { - 'W402': messages.UnusedImport, - 'W403': messages.ImportShadowedByLoopVar, - 'W404': messages.ImportStarUsed, - 'W405': messages.LateFutureImport, + 'W402': (messages.UnusedImport,), + 'W403': (messages.ImportShadowedByLoopVar,), + 'W404': (messages.ImportStarUsed,), + 'W405': (messages.LateFutureImport,), 'W801': (messages.RedefinedWhileUnused, messages.RedefinedInListComp,), - 'W802': messages.UndefinedName, - 'W803': messages.UndefinedExport, + 'W802': (messages.UndefinedName,), + 'W803': (messages.UndefinedExport,), 'W804': (messages.UndefinedLocal, messages.UnusedVariable,), - 'W805': messages.DuplicateArgument, - 'W806': messages.Redefined, + 'W805': (messages.DuplicateArgument,), + 'W806': (messages.Redefined,), } class Flake8Reporter(reporter.Reporter): """Our own instance of a Reporter so that we can silence some messages.""" - #class_mapping = dict((k, c) for (c, v) in error_mapping.items() for k in - #v) + class_mapping = dict((k, c) for (c, v) in error_mapping.items() for k in v) def __init__(self, ignore=None): super(Flake8Reporter, self).__init__(sys.stdout, sys.stderr) self.ignore = ignore or [] @@ -194,5 +193,16 @@ class Flake8Reporter(reporter.Reporter): if (any(isinstance(message, c) for c in classes) or skip_warning(message)): return + m = self.to_str(message) + i = m.rfind(':') + 1 + message = '{0} {1}{2}'.format( + m[:i], self.class_mapping[message.__class__], m[i:] + ) super(Flake8Reporter, self).flake(message) + + def to_str(self, message): + try: + return unicode(message) + except NameError: + return str(message) From 42231ff1ecd5459402afebf3d5d2f21e579cd161 Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 8 Feb 2013 18:19:26 -0500 Subject: [PATCH 3/4] Fixes #58 --- flake8/util.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/flake8/util.py b/flake8/util.py index 3d16594..d98c0ba 100644 --- a/flake8/util.py +++ b/flake8/util.py @@ -123,7 +123,13 @@ def skip_warning(warning, ignore=[]): def skip_line(line): - return line.strip().lower().endswith('# noqa') + def _noqa(line): + return line.strip().lower().endswith('# noqa') + skip = _noqa(line) + if not skip: + i = line.rfind(' #') + skip = _noqa(line[:i]) if i > 0 else False + return skip _NOQA = re.compile(r'flake8[:=]\s*noqa', re.I | re.M) From 5ab98117ba9fdab39a288e5922cdfbebf6031afd Mon Sep 17 00:00:00 2001 From: Ian Cordasco Date: Fri, 8 Feb 2013 18:26:18 -0500 Subject: [PATCH 4/4] Fixes #66 flake8 will defer to local configurations first but then will check global per-user configuration --- flake8/util.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/flake8/util.py b/flake8/util.py index d98c0ba..0d0f971 100644 --- a/flake8/util.py +++ b/flake8/util.py @@ -49,7 +49,9 @@ def get_parser(): def read_config(opts, opt_parser): - configs = ('.flake8', '.pep8', 'tox.ini', 'setup.cfg',) + configs = ('.flake8', '.pep8', 'tox.ini', 'setup.cfg', + os.path.expanduser(r'~\.flake8'), + os.path.join(os.path.expanduser('~/.config'), 'flake8') parser = ConfigParser() files_found = parser.read(configs) if not (files_found and parser.has_section('flake8')):