Use the flake8 tool on the master branch

This commit is contained in:
Stephane Wirtel 2010-08-12 17:07:03 +02:00
parent 4f6d1eb6cc
commit ed429af48c
9 changed files with 91 additions and 132 deletions

View file

@ -10,6 +10,7 @@ import pep8
checker = __import__('flake8.checker').checker checker = __import__('flake8.checker').checker
def check(codeString, filename): def check(codeString, filename):
""" """
Check the Python source given by C{codeString} for flakes. Check the Python source given by C{codeString} for flakes.
@ -65,11 +66,13 @@ def check(codeString, filename):
return valid_warnings return valid_warnings
def _noqa(warning): def _noqa(warning):
# XXX quick dirty hack, just need to keep the line in the warning # XXX quick dirty hack, just need to keep the line in the warning
line = open(warning.filename).readlines()[warning.lineno-1] line = open(warning.filename).readlines()[warning.lineno - 1]
return line.strip().lower().endswith('# noqa') return line.strip().lower().endswith('# noqa')
def checkPath(filename): def checkPath(filename):
""" """
Check the given path, printing out any warnings detected. Check the given path, printing out any warnings detected.
@ -105,5 +108,4 @@ def main():
stdin = sys.stdin.read() stdin = sys.stdin.read()
warnings += check(stdin, '<stdin>') warnings += check(stdin, '<stdin>')
raise SystemExit(warnings > 0) raise SystemExit(warnings > 0)

View file

@ -14,10 +14,11 @@ try:
import ast import ast
iter_child_nodes = ast.iter_child_nodes iter_child_nodes = ast.iter_child_nodes
except (ImportError, AttributeError): except (ImportError, AttributeError):
def iter_child_nodes(node, astcls=_ast.AST): def iter_child_nodes(node, astcls=_ast.AST):
""" """
Yield all direct child nodes of *node*, that is, all fields that are nodes Yield all direct child nodes of *node*, that is, all fields that are
and all items of fields that are lists of nodes. nodes and all items of fields that are lists of nodes.
""" """
for name in node._fields: for name in node._fields:
field = getattr(node, name, None) field = getattr(node, name, None)
@ -45,24 +46,21 @@ class Binding(object):
self.source = source self.source = source
self.used = False self.used = False
def __str__(self): def __str__(self):
return self.name return self.name
def __repr__(self): def __repr__(self):
return '<%s object %r from line %r at 0x%x>' % (self.__class__.__name__, return '<%s object %r from line %r at 0x%x>' % (
self.name, self.__class__.__name__,
self.source.lineno, self.name,
id(self)) self.source.lineno,
id(self))
class UnBinding(Binding): class UnBinding(Binding):
'''Created by the 'del' operator.''' '''Created by the 'del' operator.'''
class Importation(Binding): class Importation(Binding):
""" """
A binding created by an import statement. A binding created by an import statement.
@ -77,14 +75,12 @@ class Importation(Binding):
super(Importation, self).__init__(name, source) super(Importation, self).__init__(name, source)
class Argument(Binding): class Argument(Binding):
""" """
Represents binding a name as an argument. Represents binding a name as an argument.
""" """
class Assignment(Binding): class Assignment(Binding):
""" """
Represents binding a name with an explicit assignment. Represents binding a name with an explicit assignment.
@ -95,12 +91,10 @@ class Assignment(Binding):
""" """
class FunctionDefinition(Binding): class FunctionDefinition(Binding):
pass pass
class ExportBinding(Binding): class ExportBinding(Binding):
""" """
A binding created by an C{__all__} assignment. If the names in the list A binding created by an C{__all__} assignment. If the names in the list
@ -127,25 +121,22 @@ class ExportBinding(Binding):
return names return names
class Scope(dict): class Scope(dict):
importStarred = False # set to True when import * is found importStarred = False # set to True when import * is found
def __repr__(self): def __repr__(self):
return '<%s at 0x%x %s>' % (self.__class__.__name__, id(self), dict.__repr__(self)) return '<%s at 0x%x %s>' % (self.__class__.__name__,
id(self),
dict.__repr__(self))
def __init__(self): def __init__(self):
super(Scope, self).__init__() super(Scope, self).__init__()
class ClassScope(Scope): class ClassScope(Scope):
pass pass
class FunctionScope(Scope): class FunctionScope(Scope):
""" """
I represent a name scope for a function. I represent a name scope for a function.
@ -157,7 +148,6 @@ class FunctionScope(Scope):
self.globals = {} self.globals = {}
class ModuleScope(Scope): class ModuleScope(Scope):
pass pass
@ -166,7 +156,6 @@ class ModuleScope(Scope):
_MAGIC_GLOBALS = ['__file__', '__builtins__'] _MAGIC_GLOBALS = ['__file__', '__builtins__']
class Checker(object): class Checker(object):
""" """
I check the cleanliness and sanity of Python code. I check the cleanliness and sanity of Python code.
@ -204,7 +193,6 @@ class Checker(object):
self.popScope() self.popScope()
self.check_dead_scopes() self.check_dead_scopes()
def deferFunction(self, callable): def deferFunction(self, callable):
''' '''
Schedule a function handler to be called just before completion. Schedule a function handler to be called just before completion.
@ -216,7 +204,6 @@ class Checker(object):
''' '''
self._deferredFunctions.append((callable, self.scopeStack[:])) self._deferredFunctions.append((callable, self.scopeStack[:]))
def deferAssignment(self, callable): def deferAssignment(self, callable):
""" """
Schedule an assignment handler to be called just after deferred Schedule an assignment handler to be called just after deferred
@ -224,7 +211,6 @@ class Checker(object):
""" """
self._deferredAssignments.append((callable, self.scopeStack[:])) self._deferredAssignments.append((callable, self.scopeStack[:]))
def _runDeferred(self, deferred): def _runDeferred(self, deferred):
""" """
Run the callables in C{deferred} using their associated scope stack. Run the callables in C{deferred} using their associated scope stack.
@ -233,7 +219,6 @@ class Checker(object):
self.scopeStack = scope self.scopeStack = scope
handler() handler()
def scope(self): def scope(self):
return self.scopeStack[-1] return self.scopeStack[-1]
scope = property(scope) scope = property(scope)
@ -241,7 +226,6 @@ class Checker(object):
def popScope(self): def popScope(self):
self.dead_scopes.append(self.scopeStack.pop()) self.dead_scopes.append(self.scopeStack.pop())
def check_dead_scopes(self): def check_dead_scopes(self):
""" """
Look at scopes which have been fully examined and report names in them Look at scopes which have been fully examined and report names in them
@ -271,7 +255,6 @@ class Checker(object):
importation.source.lineno, importation.source.lineno,
importation.name) importation.name)
def pushFunctionScope(self): def pushFunctionScope(self):
self.scopeStack.append(FunctionScope()) self.scopeStack.append(FunctionScope())
@ -352,18 +335,21 @@ class Checker(object):
if (isinstance(self.scope.get(value.name), FunctionDefinition) if (isinstance(self.scope.get(value.name), FunctionDefinition)
and isinstance(value, FunctionDefinition)): and isinstance(value, FunctionDefinition)):
self.report(messages.RedefinedFunction, self.report(messages.RedefinedFunction,
lineno, value.name, self.scope[value.name].source.lineno) lineno, value.name,
self.scope[value.name].source.lineno)
if not isinstance(self.scope, ClassScope): if not isinstance(self.scope, ClassScope):
for scope in self.scopeStack[::-1]: for scope in self.scopeStack[::-1]:
existing = scope.get(value.name) existing = scope.get(value.name)
if (isinstance(existing, Importation) if (isinstance(existing, Importation)
and not existing.used and not existing.used
and (not isinstance(value, Importation) or value.fullName == existing.fullName) and (not isinstance(value, Importation) \
or value.fullName == existing.fullName)
and reportRedef): and reportRedef):
self.report(messages.RedefinedWhileUnused, self.report(messages.RedefinedWhileUnused,
lineno, value.name, scope[value.name].source.lineno) lineno, value.name,
scope[value.name].source.lineno)
if isinstance(value, UnBinding): if isinstance(value, UnBinding):
try: try:
@ -400,6 +386,7 @@ class Checker(object):
Process bindings for loop variables. Process bindings for loop variables.
""" """
vars = [] vars = []
def collectLoopVars(n): def collectLoopVars(n):
if isinstance(n, _ast.Name): if isinstance(n, _ast.Name):
vars.append(n.id) vars.append(n.id)
@ -461,10 +448,14 @@ class Checker(object):
# the special name __path__ is valid only in packages # the special name __path__ is valid only in packages
pass pass
else: else:
self.report(messages.UndefinedName, node.lineno, node.id) self.report(messages.UndefinedName,
node.lineno,
node.id)
elif isinstance(node.ctx, (_ast.Store, _ast.AugStore)): elif isinstance(node.ctx, (_ast.Store, _ast.AugStore)):
# if the name hasn't already been defined in the current scope # if the name hasn't already been defined in the current scope
if isinstance(self.scope, FunctionScope) and node.id not in self.scope: if isinstance(self.scope, FunctionScope) and \
node.id not in self.scope:
# for each function or module scope above us # for each function or module scope above us
for scope in self.scopeStack[:-1]: for scope in self.scopeStack[:-1]:
if not isinstance(scope, (FunctionScope, ModuleScope)): if not isinstance(scope, (FunctionScope, ModuleScope)):
@ -484,7 +475,10 @@ class Checker(object):
break break
if isinstance(node.parent, if isinstance(node.parent,
(_ast.For, _ast.comprehension, _ast.Tuple, _ast.List)): (_ast.For,
_ast.comprehension,
_ast.Tuple,
_ast.List)):
binding = Binding(node.id, node) binding = Binding(node.id, node)
elif (node.id == '__all__' and elif (node.id == '__all__' and
isinstance(self.scope, ModuleScope)): isinstance(self.scope, ModuleScope)):
@ -501,12 +495,11 @@ class Checker(object):
else: else:
self.addBinding(node.lineno, UnBinding(node.id, node)) self.addBinding(node.lineno, UnBinding(node.id, node))
else: else:
# must be a Param context -- this only happens for names in function # must be a Param context -- this only happens for names
# arguments, but these aren't dispatched through here # in function arguments, but these aren't dispatched through here
raise RuntimeError( raise RuntimeError(
"Got impossible expression context: %r" % (node.ctx,)) "Got impossible expression context: %r" % (node.ctx,))
def FUNCTIONDEF(self, node): def FUNCTIONDEF(self, node):
# the decorators attribute is called decorator_list as of Python 2.6 # the decorators attribute is called decorator_list as of Python 2.6
if hasattr(node, 'decorators'): if hasattr(node, 'decorators'):
@ -543,7 +536,8 @@ class Checker(object):
if node.args.kwarg: if node.args.kwarg:
args.append(node.args.kwarg) args.append(node.args.kwarg)
for name in args: for name in args:
self.addBinding(node.lineno, Argument(name, node), reportRedef=False) self.addBinding(node.lineno, Argument(name, node),
reportRedef=False)
if isinstance(node.body, list): if isinstance(node.body, list):
# case for FunctionDefs # case for FunctionDefs
for stmt in node.body: for stmt in node.body:
@ -551,6 +545,7 @@ class Checker(object):
else: else:
# case for Lambdas # case for Lambdas
self.handleNode(node.body, node) self.handleNode(node.body, node)
def checkUnusedAssignments(): def checkUnusedAssignments():
""" """
Check to see if any assignments have not been used. Check to see if any assignments have not been used.
@ -565,7 +560,6 @@ class Checker(object):
self.deferFunction(runFunction) self.deferFunction(runFunction)
def CLASSDEF(self, node): def CLASSDEF(self, node):
""" """
Check names used in a class definition, including its decorators, base Check names used in a class definition, including its decorators, base
@ -589,8 +583,9 @@ class Checker(object):
self.handleNode(target, node) self.handleNode(target, node)
def AUGASSIGN(self, node): def AUGASSIGN(self, node):
# AugAssign is awkward: must set the context explicitly and visit twice, # AugAssign is awkward: must set the context explicitly
# once with AugLoad context, once with AugStore context # and visit twice, once with AugLoad context, once with
# AugStore context
node.target.ctx = _ast.AugLoad() node.target.ctx = _ast.AugLoad()
self.handleNode(node.target, node) self.handleNode(node.target, node)
self.handleNode(node.value, node) self.handleNode(node.value, node)

View file

@ -1,17 +1,22 @@
# (c) 2005 Divmod, Inc. See LICENSE file for details # (c) 2005 Divmod, Inc. See LICENSE file for details
class Message(object): class Message(object):
message = '' message = ''
message_args = () message_args = ()
def __init__(self, filename, lineno): def __init__(self, filename, lineno):
self.filename = filename self.filename = filename
self.lineno = lineno self.lineno = lineno
def __str__(self): def __str__(self):
return '%s:%s: %s' % (self.filename, self.lineno, self.message % self.message_args) return '%s:%s: %s' % (self.filename, self.lineno,
self.message % self.message_args)
class UnusedImport(Message): class UnusedImport(Message):
message = '%r imported but unused' message = '%r imported but unused'
def __init__(self, filename, lineno, name): def __init__(self, filename, lineno, name):
Message.__init__(self, filename, lineno) Message.__init__(self, filename, lineno)
self.message_args = (name,) self.message_args = (name,)
@ -19,6 +24,7 @@ class UnusedImport(Message):
class RedefinedWhileUnused(Message): class RedefinedWhileUnused(Message):
message = 'redefinition of unused %r from line %r' message = 'redefinition of unused %r from line %r'
def __init__(self, filename, lineno, name, orig_lineno): def __init__(self, filename, lineno, name, orig_lineno):
Message.__init__(self, filename, lineno) Message.__init__(self, filename, lineno)
self.message_args = (name, orig_lineno) self.message_args = (name, orig_lineno)
@ -26,6 +32,7 @@ class RedefinedWhileUnused(Message):
class ImportShadowedByLoopVar(Message): class ImportShadowedByLoopVar(Message):
message = 'import %r from line %r shadowed by loop variable' message = 'import %r from line %r shadowed by loop variable'
def __init__(self, filename, lineno, name, orig_lineno): def __init__(self, filename, lineno, name, orig_lineno):
Message.__init__(self, filename, lineno) Message.__init__(self, filename, lineno)
self.message_args = (name, orig_lineno) self.message_args = (name, orig_lineno)
@ -33,6 +40,7 @@ class ImportShadowedByLoopVar(Message):
class ImportStarUsed(Message): class ImportStarUsed(Message):
message = "'from %s import *' used; unable to detect undefined names" message = "'from %s import *' used; unable to detect undefined names"
def __init__(self, filename, lineno, modname): def __init__(self, filename, lineno, modname):
Message.__init__(self, filename, lineno) Message.__init__(self, filename, lineno)
self.message_args = (modname,) self.message_args = (modname,)
@ -40,22 +48,24 @@ class ImportStarUsed(Message):
class UndefinedName(Message): class UndefinedName(Message):
message = 'undefined name %r' message = 'undefined name %r'
def __init__(self, filename, lineno, name): def __init__(self, filename, lineno, name):
Message.__init__(self, filename, lineno) Message.__init__(self, filename, lineno)
self.message_args = (name,) self.message_args = (name,)
class UndefinedExport(Message): class UndefinedExport(Message):
message = 'undefined name %r in __all__' message = 'undefined name %r in __all__'
def __init__(self, filename, lineno, name): def __init__(self, filename, lineno, name):
Message.__init__(self, filename, lineno) Message.__init__(self, filename, lineno)
self.message_args = (name,) self.message_args = (name,)
class UndefinedLocal(Message): class UndefinedLocal(Message):
message = "local variable %r (defined in enclosing scope on line %r) referenced before assignment" message = "local variable %r (defined in enclosing scope on line %r) " \
"referenced before assignment"
def __init__(self, filename, lineno, name, orig_lineno): def __init__(self, filename, lineno, name, orig_lineno):
Message.__init__(self, filename, lineno) Message.__init__(self, filename, lineno)
self.message_args = (name, orig_lineno) self.message_args = (name, orig_lineno)
@ -63,6 +73,7 @@ class UndefinedLocal(Message):
class DuplicateArgument(Message): class DuplicateArgument(Message):
message = 'duplicate argument %r in function definition' message = 'duplicate argument %r in function definition'
def __init__(self, filename, lineno, name): def __init__(self, filename, lineno, name):
Message.__init__(self, filename, lineno) Message.__init__(self, filename, lineno)
self.message_args = (name,) self.message_args = (name,)
@ -70,6 +81,7 @@ class DuplicateArgument(Message):
class RedefinedFunction(Message): class RedefinedFunction(Message):
message = 'redefinition of function %r from line %r' message = 'redefinition of function %r from line %r'
def __init__(self, filename, lineno, name, orig_lineno): def __init__(self, filename, lineno, name, orig_lineno):
Message.__init__(self, filename, lineno) Message.__init__(self, filename, lineno)
self.message_args = (name, orig_lineno) self.message_args = (name, orig_lineno)
@ -77,6 +89,7 @@ class RedefinedFunction(Message):
class LateFutureImport(Message): class LateFutureImport(Message):
message = 'future import(s) %r after other statements' message = 'future import(s) %r after other statements'
def __init__(self, filename, lineno, names): def __init__(self, filename, lineno, names):
Message.__init__(self, filename, lineno) Message.__init__(self, filename, lineno)
self.message_args = (names,) self.message_args = (names,)
@ -89,6 +102,7 @@ class UnusedVariable(Message):
""" """
message = 'local variable %r is assigned to but never used' message = 'local variable %r is assigned to but never used'
def __init__(self, filename, lineno, names): def __init__(self, filename, lineno, names):
Message.__init__(self, filename, lineno) Message.__init__(self, filename, lineno)
self.message_args = (names,) self.message_args = (names,)

View file

@ -985,6 +985,7 @@ def input_file(filename):
message("%s: error %s not found" % (filename, code)) message("%s: error %s not found" % (filename, code))
return errors return errors
def input_dir(dirname): def input_dir(dirname):
""" """
Check all Python source files in this directory and all subdirectories. Check all Python source files in this directory and all subdirectories.

View file

@ -23,5 +23,6 @@ for input:
expected outputs: expected outputs:
%s %s
but got: but got:
%s''' % (input, repr(expectedOutputs), '\n'.join([str(o) for o in w.messages]))) %s''' % (input, repr(expectedOutputs), '\n'.join(map(str, w.messages))))
return w return w

View file

@ -4,6 +4,7 @@ from sys import version_info
from pyflakes import messages as m from pyflakes import messages as m
from pyflakes.test import harness from pyflakes.test import harness
class Test(harness.Test): class Test(harness.Test):
def test_unusedImport(self): def test_unusedImport(self):
@ -11,8 +12,10 @@ class Test(harness.Test):
self.flakes('from baz import fu, bar', m.UnusedImport, m.UnusedImport) self.flakes('from baz import fu, bar', m.UnusedImport, m.UnusedImport)
def test_aliasedImport(self): def test_aliasedImport(self):
self.flakes('import fu as FU, bar as FU', m.RedefinedWhileUnused, m.UnusedImport) self.flakes('import fu as FU, bar as FU',
self.flakes('from moo import fu as FU, bar as FU', m.RedefinedWhileUnused, m.UnusedImport) m.RedefinedWhileUnused, m.UnusedImport)
self.flakes('from moo import fu as FU, bar as FU',
m.RedefinedWhileUnused, m.UnusedImport)
def test_usedImport(self): def test_usedImport(self):
self.flakes('import fu; print fu') self.flakes('import fu; print fu')
@ -51,7 +54,6 @@ class Test(harness.Test):
pass pass
''', m.RedefinedWhileUnused) ''', m.RedefinedWhileUnused)
def test_redefinedBySubclass(self): def test_redefinedBySubclass(self):
""" """
If an imported name is redefined by a class statement which also uses If an imported name is redefined by a class statement which also uses
@ -63,7 +65,6 @@ class Test(harness.Test):
pass pass
''') ''')
def test_redefinedInClass(self): def test_redefinedInClass(self):
""" """
Test that shadowing a global with a class attribute does not produce a Test that shadowing a global with a class attribute does not produce a
@ -306,8 +307,8 @@ class Test(harness.Test):
self.flakes('import fu; [1 for _ in range(1) if fu]') self.flakes('import fu; [1 for _ in range(1) if fu]')
def test_redefinedByListComp(self): def test_redefinedByListComp(self):
self.flakes('import fu; [1 for fu in range(1)]', m.RedefinedWhileUnused) self.flakes('import fu; [1 for fu in range(1)]',
m.RedefinedWhileUnused)
def test_usedInTryFinally(self): def test_usedInTryFinally(self):
self.flakes(''' self.flakes('''
@ -390,7 +391,6 @@ class Test(harness.Test):
def test_importStar(self): def test_importStar(self):
self.flakes('from fu import *', m.ImportStarUsed) self.flakes('from fu import *', m.ImportStarUsed)
def test_packageImport(self): def test_packageImport(self):
""" """
If a dotted name is imported and used, no warning is reported. If a dotted name is imported and used, no warning is reported.
@ -400,7 +400,6 @@ class Test(harness.Test):
fu.bar fu.bar
''') ''')
def test_unusedPackageImport(self): def test_unusedPackageImport(self):
""" """
If a dotted name is imported and not used, an unused import warning is If a dotted name is imported and not used, an unused import warning is
@ -408,7 +407,6 @@ class Test(harness.Test):
""" """
self.flakes('import fu.bar', m.UnusedImport) self.flakes('import fu.bar', m.UnusedImport)
def test_duplicateSubmoduleImport(self): def test_duplicateSubmoduleImport(self):
""" """
If a submodule of a package is imported twice, an unused import warning If a submodule of a package is imported twice, an unused import warning
@ -424,7 +422,6 @@ class Test(harness.Test):
fu.bar fu.bar
''', m.RedefinedWhileUnused) ''', m.RedefinedWhileUnused)
def test_differentSubmoduleImport(self): def test_differentSubmoduleImport(self):
""" """
If two different submodules of a package are imported, no duplicate If two different submodules of a package are imported, no duplicate
@ -524,7 +521,6 @@ class Test(harness.Test):
''', m.LateFutureImport) ''', m.LateFutureImport)
class TestSpecialAll(harness.Test): class TestSpecialAll(harness.Test):
""" """
Tests for suppression of unused import warnings by C{__all__}. Tests for suppression of unused import warnings by C{__all__}.
@ -540,7 +536,6 @@ class TestSpecialAll(harness.Test):
__all__ = ["bar"] __all__ = ["bar"]
''', m.UnusedImport, m.UnusedVariable) ''', m.UnusedImport, m.UnusedVariable)
def test_ignoredInClass(self): def test_ignoredInClass(self):
""" """
An C{__all__} definition does not suppress unused import warnings in a An C{__all__} definition does not suppress unused import warnings in a
@ -552,7 +547,6 @@ class TestSpecialAll(harness.Test):
__all__ = ["bar"] __all__ = ["bar"]
''', m.UnusedImport) ''', m.UnusedImport)
def test_warningSuppressed(self): def test_warningSuppressed(self):
""" """
If a name is imported and unused but is named in C{__all__}, no warning If a name is imported and unused but is named in C{__all__}, no warning
@ -563,7 +557,6 @@ class TestSpecialAll(harness.Test):
__all__ = ["foo"] __all__ = ["foo"]
''') ''')
def test_unrecognizable(self): def test_unrecognizable(self):
""" """
If C{__all__} is defined in a way that can't be recognized statically, If C{__all__} is defined in a way that can't be recognized statically,
@ -578,7 +571,6 @@ class TestSpecialAll(harness.Test):
__all__ = [] + ["foo"] __all__ = [] + ["foo"]
''', m.UnusedImport) ''', m.UnusedImport)
def test_unboundExported(self): def test_unboundExported(self):
""" """
If C{__all__} includes a name which is not bound, a warning is emitted. If C{__all__} includes a name which is not bound, a warning is emitted.
@ -594,7 +586,6 @@ class TestSpecialAll(harness.Test):
__all__ = ["foo"] __all__ = ["foo"]
''', filename=filename) ''', filename=filename)
def test_usedInGenExp(self): def test_usedInGenExp(self):
""" """
Using a global in a generator expression results in no warnings. Using a global in a generator expression results in no warnings.
@ -602,14 +593,13 @@ class TestSpecialAll(harness.Test):
self.flakes('import fu; (fu for _ in range(1))') self.flakes('import fu; (fu for _ in range(1))')
self.flakes('import fu; (1 for _ in range(1) if fu)') self.flakes('import fu; (1 for _ in range(1) if fu)')
def test_redefinedByGenExp(self): def test_redefinedByGenExp(self):
""" """
Re-using a global name as the loop variable for a generator Re-using a global name as the loop variable for a generator
expression results in a redefinition warning. expression results in a redefinition warning.
""" """
self.flakes('import fu; (1 for fu in range(1))', m.RedefinedWhileUnused) self.flakes('import fu; (1 for fu in range(1))',
m.RedefinedWhileUnused)
def test_usedAsDecorator(self): def test_usedAsDecorator(self):
""" """
@ -645,7 +635,6 @@ class Python26Tests(harness.Test):
if version_info < (2, 6): if version_info < (2, 6):
skip = "Python 2.6 required for class decorator tests." skip = "Python 2.6 required for class decorator tests."
def test_usedAsClassDecorator(self): def test_usedAsClassDecorator(self):
""" """
Using an imported name as a class decorator results in no warnings, Using an imported name as a class decorator results in no warnings,

View file

@ -23,7 +23,8 @@ class Test(harness.Test):
a; a=1 a; a=1
f() f()
''', m.UndefinedName) ''', m.UndefinedName)
test_localReferencedBeforeAssignment.todo = 'this requires finding all assignments in the function body first' test_localReferencedBeforeAssignment.todo = 'this requires finding all ' \
'assignments in the function body first'
def test_redefinedFunction(self): def test_redefinedFunction(self):
""" """
@ -73,7 +74,6 @@ class Test(harness.Test):
'''Don't die on unary +''' '''Don't die on unary +'''
self.flakes('+1') self.flakes('+1')
def test_undefinedBaseClass(self): def test_undefinedBaseClass(self):
""" """
If a name in the base list of a class definition is undefined, a If a name in the base list of a class definition is undefined, a
@ -84,7 +84,6 @@ class Test(harness.Test):
pass pass
''', m.UndefinedName) ''', m.UndefinedName)
def test_classNameUndefinedInClassBody(self): def test_classNameUndefinedInClassBody(self):
""" """
If a class name is used in the body of that class's definition and If a class name is used in the body of that class's definition and
@ -95,7 +94,6 @@ class Test(harness.Test):
foo foo
''', m.UndefinedName) ''', m.UndefinedName)
def test_classNameDefinedPreviously(self): def test_classNameDefinedPreviously(self):
""" """
If a class name is used in the body of that class's definition and If a class name is used in the body of that class's definition and
@ -108,7 +106,6 @@ class Test(harness.Test):
foo foo
''') ''')
def test_comparison(self): def test_comparison(self):
""" """
If a defined name is used on either side of any of the six comparison If a defined name is used on either side of any of the six comparison
@ -125,7 +122,6 @@ class Test(harness.Test):
x > y x > y
''') ''')
def test_identity(self): def test_identity(self):
""" """
If a deefined name is used on either side of an identity test, no If a deefined name is used on either side of an identity test, no
@ -138,7 +134,6 @@ class Test(harness.Test):
x is not y x is not y
''') ''')
def test_containment(self): def test_containment(self):
""" """
If a defined name is used on either side of a containment test, no If a defined name is used on either side of a containment test, no
@ -151,7 +146,6 @@ class Test(harness.Test):
x not in y x not in y
''') ''')
def test_loopControl(self): def test_loopControl(self):
""" """
break and continue statements are supported. break and continue statements are supported.
@ -165,7 +159,6 @@ class Test(harness.Test):
continue continue
''') ''')
def test_ellipsis(self): def test_ellipsis(self):
""" """
Ellipsis in a slice is supported. Ellipsis in a slice is supported.
@ -174,7 +167,6 @@ class Test(harness.Test):
[1, 2][...] [1, 2][...]
''') ''')
def test_extendedSlice(self): def test_extendedSlice(self):
""" """
Extended slices are supported. Extended slices are supported.
@ -185,7 +177,6 @@ class Test(harness.Test):
''') ''')
class TestUnusedAssignment(harness.Test): class TestUnusedAssignment(harness.Test):
""" """
Tests for warning about unused assignments. Tests for warning about unused assignments.
@ -201,7 +192,6 @@ class TestUnusedAssignment(harness.Test):
b = 1 b = 1
''', m.UnusedVariable) ''', m.UnusedVariable)
def test_assignToGlobal(self): def test_assignToGlobal(self):
""" """
Assigning to a global and then not using that global is perfectly Assigning to a global and then not using that global is perfectly
@ -214,7 +204,6 @@ class TestUnusedAssignment(harness.Test):
b = 1 b = 1
''') ''')
def test_assignToMember(self): def test_assignToMember(self):
""" """
Assigning to a member of another object and then not using that member Assigning to a member of another object and then not using that member
@ -230,7 +219,6 @@ class TestUnusedAssignment(harness.Test):
b.foo = 1 b.foo = 1
''') ''')
def test_assignInForLoop(self): def test_assignInForLoop(self):
""" """
Don't warn when a variable in a for loop is assigned to but not used. Don't warn when a variable in a for loop is assigned to but not used.
@ -241,7 +229,6 @@ class TestUnusedAssignment(harness.Test):
pass pass
''') ''')
def test_assignInListComprehension(self): def test_assignInListComprehension(self):
""" """
Don't warn when a variable in a list comprehension is assigned to but Don't warn when a variable in a list comprehension is assigned to but
@ -252,17 +239,16 @@ class TestUnusedAssignment(harness.Test):
[None for i in range(10)] [None for i in range(10)]
''') ''')
def test_generatorExpression(self): def test_generatorExpression(self):
""" """
Don't warn when a variable in a generator expression is assigned to but not used. Don't warn when a variable in a generator expression is assigned to
but not used.
""" """
self.flakes(''' self.flakes('''
def f(): def f():
(None for i in range(10)) (None for i in range(10))
''') ''')
def test_assignmentInsideLoop(self): def test_assignmentInsideLoop(self):
""" """
Don't warn when a variable assignment occurs lexically after its use. Don't warn when a variable assignment occurs lexically after its use.
@ -276,7 +262,6 @@ class TestUnusedAssignment(harness.Test):
x = i * 2 x = i * 2
''') ''')
def test_tupleUnpacking(self): def test_tupleUnpacking(self):
""" """
Don't warn when a variable included in tuple unpacking is unused. It's Don't warn when a variable included in tuple unpacking is unused. It's
@ -288,7 +273,6 @@ class TestUnusedAssignment(harness.Test):
(x, y) = 1, 2 (x, y) = 1, 2
''') ''')
def test_listUnpacking(self): def test_listUnpacking(self):
""" """
Don't warn when a variable included in list unpacking is unused. Don't warn when a variable included in list unpacking is unused.
@ -298,7 +282,6 @@ class TestUnusedAssignment(harness.Test):
[x, y] = [1, 2] [x, y] = [1, 2]
''') ''')
def test_closedOver(self): def test_closedOver(self):
""" """
Don't warn when the assignment is used in an inner function. Don't warn when the assignment is used in an inner function.
@ -311,7 +294,6 @@ class TestUnusedAssignment(harness.Test):
return bar return bar
''') ''')
def test_doubleClosedOver(self): def test_doubleClosedOver(self):
""" """
Don't warn when the assignment is used in an inner function, even if Don't warn when the assignment is used in an inner function, even if
@ -327,7 +309,6 @@ class TestUnusedAssignment(harness.Test):
''') ''')
class Python25Test(harness.Test): class Python25Test(harness.Test):
""" """
Tests for checking of syntax only available in Python 2.5 and newer. Tests for checking of syntax only available in Python 2.5 and newer.
@ -343,7 +324,6 @@ class Python25Test(harness.Test):
self.flakes("a = foo if True else 'oink'", m.UndefinedName) self.flakes("a = foo if True else 'oink'", m.UndefinedName)
self.flakes("a = 'moo' if True else bar", m.UndefinedName) self.flakes("a = 'moo' if True else bar", m.UndefinedName)
def test_withStatementNoNames(self): def test_withStatementNoNames(self):
""" """
No warnings are emitted for using inside or after a nameless C{with} No warnings are emitted for using inside or after a nameless C{with}
@ -369,7 +349,6 @@ class Python25Test(harness.Test):
bar bar
''') ''')
def test_withStatementAttributeName(self): def test_withStatementAttributeName(self):
""" """
No warnings are emitted for using an attribute as the target of a No warnings are emitted for using an attribute as the target of a
@ -382,7 +361,6 @@ class Python25Test(harness.Test):
pass pass
''') ''')
def test_withStatementSubscript(self): def test_withStatementSubscript(self):
""" """
No warnings are emitted for using a subscript as the target of a No warnings are emitted for using a subscript as the target of a
@ -395,7 +373,6 @@ class Python25Test(harness.Test):
pass pass
''') ''')
def test_withStatementSubscriptUndefined(self): def test_withStatementSubscriptUndefined(self):
""" """
An undefined name warning is emitted if the subscript used as the An undefined name warning is emitted if the subscript used as the
@ -408,7 +385,6 @@ class Python25Test(harness.Test):
pass pass
''', m.UndefinedName) ''', m.UndefinedName)
def test_withStatementTupleNames(self): def test_withStatementTupleNames(self):
""" """
No warnings are emitted for using any of the tuple of names defined by No warnings are emitted for using any of the tuple of names defined by
@ -421,7 +397,6 @@ class Python25Test(harness.Test):
bar, baz bar, baz
''') ''')
def test_withStatementListNames(self): def test_withStatementListNames(self):
""" """
No warnings are emitted for using any of the list of names defined by a No warnings are emitted for using any of the list of names defined by a
@ -434,7 +409,6 @@ class Python25Test(harness.Test):
bar, baz bar, baz
''') ''')
def test_withStatementComplicatedTarget(self): def test_withStatementComplicatedTarget(self):
""" """
If the target of a C{with} statement uses any or all of the valid forms If the target of a C{with} statement uses any or all of the valid forms
@ -451,7 +425,6 @@ class Python25Test(harness.Test):
a, b, c, d, e, g, h, i a, b, c, d, e, g, h, i
''') ''')
def test_withStatementSingleNameUndefined(self): def test_withStatementSingleNameUndefined(self):
""" """
An undefined name warning is emitted if the name first defined by a An undefined name warning is emitted if the name first defined by a
@ -464,7 +437,6 @@ class Python25Test(harness.Test):
pass pass
''', m.UndefinedName) ''', m.UndefinedName)
def test_withStatementTupleNamesUndefined(self): def test_withStatementTupleNamesUndefined(self):
""" """
An undefined name warning is emitted if a name first defined by a the An undefined name warning is emitted if a name first defined by a the
@ -478,7 +450,6 @@ class Python25Test(harness.Test):
pass pass
''', m.UndefinedName) ''', m.UndefinedName)
def test_withStatementSingleNameRedefined(self): def test_withStatementSingleNameRedefined(self):
""" """
A redefined name warning is emitted if a name bound by an import is A redefined name warning is emitted if a name bound by an import is
@ -491,7 +462,6 @@ class Python25Test(harness.Test):
pass pass
''', m.RedefinedWhileUnused) ''', m.RedefinedWhileUnused)
def test_withStatementTupleNamesRedefined(self): def test_withStatementTupleNamesRedefined(self):
""" """
A redefined name warning is emitted if a name bound by an import is A redefined name warning is emitted if a name bound by an import is
@ -505,7 +475,6 @@ class Python25Test(harness.Test):
pass pass
''', m.RedefinedWhileUnused) ''', m.RedefinedWhileUnused)
def test_withStatementUndefinedInside(self): def test_withStatementUndefinedInside(self):
""" """
An undefined name warning is emitted if a name is used inside the An undefined name warning is emitted if a name is used inside the
@ -517,7 +486,6 @@ class Python25Test(harness.Test):
baz baz
''', m.UndefinedName) ''', m.UndefinedName)
def test_withStatementNameDefinedInBody(self): def test_withStatementNameDefinedInBody(self):
""" """
A name defined in the body of a C{with} statement can be used after A name defined in the body of a C{with} statement can be used after
@ -530,7 +498,6 @@ class Python25Test(harness.Test):
baz baz
''') ''')
def test_withStatementUndefinedInExpression(self): def test_withStatementUndefinedInExpression(self):
""" """
An undefined name warning is emitted if a name in the I{test} An undefined name warning is emitted if a name in the I{test}
@ -549,7 +516,6 @@ class Python25Test(harness.Test):
''', m.UndefinedName) ''', m.UndefinedName)
class Python27Test(harness.Test): class Python27Test(harness.Test):
""" """
Tests for checking of syntax only available in Python 2.7 and newer. Tests for checking of syntax only available in Python 2.7 and newer.

View file

@ -11,6 +11,7 @@ from twisted.trial.unittest import TestCase
from pyflakes.scripts.pyflakes import checkPath from pyflakes.scripts.pyflakes import checkPath
def withStderrTo(stderr, f): def withStderrTo(stderr, f):
""" """
Call C{f} with C{sys.stderr} redirected to C{stderr}. Call C{f} with C{sys.stderr} redirected to C{stderr}.
@ -22,7 +23,6 @@ def withStderrTo(stderr, f):
sys.stderr = outer sys.stderr = outer
class CheckTests(TestCase): class CheckTests(TestCase):
""" """
Tests for L{check} and L{checkPath} which check a file for flakes. Tests for L{check} and L{checkPath} which check a file for flakes.
@ -37,17 +37,16 @@ class CheckTests(TestCase):
FilePath(fName).setContent("def foo():\n\tpass\n\t") FilePath(fName).setContent("def foo():\n\tpass\n\t")
self.assertFalse(checkPath(fName)) self.assertFalse(checkPath(fName))
def test_checkPathNonExisting(self): def test_checkPathNonExisting(self):
""" """
L{checkPath} handles non-existing files. L{checkPath} handles non-existing files.
""" """
err = StringIO() err = StringIO()
count = withStderrTo(err, lambda: checkPath('extremo')) count = withStderrTo(err, lambda: checkPath('extremo'))
self.assertEquals(err.getvalue(), 'extremo: No such file or directory\n') self.assertEquals(err.getvalue(),
'extremo: No such file or directory\n')
self.assertEquals(count, 1) self.assertEquals(count, 1)
def test_multilineSyntaxError(self): def test_multilineSyntaxError(self):
""" """
Source which includes a syntax error which results in the raised Source which includes a syntax error which results in the raised
@ -86,7 +85,6 @@ def baz():
^ ^
""" % (sourcePath.path,)) """ % (sourcePath.path,))
def test_eofSyntaxError(self): def test_eofSyntaxError(self):
""" """
The error reported for source files which end prematurely causing a The error reported for source files which end prematurely causing a
@ -106,7 +104,6 @@ def foo(
^ ^
""" % (sourcePath.path,)) """ % (sourcePath.path,))
def test_nonDefaultFollowsDefaultSyntaxError(self): def test_nonDefaultFollowsDefaultSyntaxError(self):
""" """
Source which has a non-default argument following a default argument Source which has a non-default argument following a default argument
@ -129,7 +126,6 @@ def foo(bar=baz, bax):
def foo(bar=baz, bax): def foo(bar=baz, bax):
""" % (sourcePath.path,)) """ % (sourcePath.path,))
def test_nonKeywordAfterKeywordSyntaxError(self): def test_nonKeywordAfterKeywordSyntaxError(self):
""" """
Source which has a non-keyword argument after a keyword argument should Source which has a non-keyword argument after a keyword argument should
@ -151,7 +147,6 @@ foo(bar=baz, bax)
foo(bar=baz, bax) foo(bar=baz, bax)
""" % (sourcePath.path,)) """ % (sourcePath.path,))
def test_permissionDenied(self): def test_permissionDenied(self):
""" """
If the a source file is not readable, this is reported on standard If the a source file is not readable, this is reported on standard
@ -166,7 +161,6 @@ foo(bar=baz, bax)
self.assertEquals( self.assertEquals(
err.getvalue(), "%s: Permission denied\n" % (sourcePath.path,)) err.getvalue(), "%s: Permission denied\n" % (sourcePath.path,))
def test_misencodedFile(self): def test_misencodedFile(self):
""" """
If a source file contains bytes which cannot be decoded, this is If a source file contains bytes which cannot be decoded, this is
@ -182,4 +176,5 @@ x = "\N{SNOWMAN}"
count = withStderrTo(err, lambda: checkPath(sourcePath.path)) count = withStderrTo(err, lambda: checkPath(sourcePath.path))
self.assertEquals(count, 1) self.assertEquals(count, 1)
self.assertEquals( self.assertEquals(
err.getvalue(), "%s: problem decoding source\n" % (sourcePath.path,)) err.getvalue(),
"%s: problem decoding source\n" % (sourcePath.path,))

View file

@ -14,7 +14,6 @@ class Test(harness.Test):
def test_definedInListComp(self): def test_definedInListComp(self):
self.flakes('[a for a in range(10) if a]') self.flakes('[a for a in range(10) if a]')
def test_functionsNeedGlobalScope(self): def test_functionsNeedGlobalScope(self):
self.flakes(''' self.flakes('''
class a: class a:
@ -26,7 +25,6 @@ class Test(harness.Test):
def test_builtins(self): def test_builtins(self):
self.flakes('range(10)') self.flakes('range(10)')
def test_magicGlobalsFile(self): def test_magicGlobalsFile(self):
""" """
Use of the C{__file__} magic global should not emit an undefined name Use of the C{__file__} magic global should not emit an undefined name
@ -34,7 +32,6 @@ class Test(harness.Test):
""" """
self.flakes('__file__') self.flakes('__file__')
def test_magicGlobalsBuiltins(self): def test_magicGlobalsBuiltins(self):
""" """
Use of the C{__builtins__} magic global should not emit an undefined Use of the C{__builtins__} magic global should not emit an undefined
@ -42,7 +39,6 @@ class Test(harness.Test):
""" """
self.flakes('__builtins__') self.flakes('__builtins__')
def test_magicGlobalsName(self): def test_magicGlobalsName(self):
""" """
Use of the C{__name__} magic global should not emit an undefined name Use of the C{__name__} magic global should not emit an undefined name
@ -50,7 +46,6 @@ class Test(harness.Test):
""" """
self.flakes('__name__') self.flakes('__name__')
def test_magicGlobalsPath(self): def test_magicGlobalsPath(self):
""" """
Use of the C{__path__} magic global should not emit an undefined name Use of the C{__path__} magic global should not emit an undefined name
@ -59,13 +54,15 @@ class Test(harness.Test):
self.flakes('__path__', m.UndefinedName) self.flakes('__path__', m.UndefinedName)
self.flakes('__path__', filename='package/__init__.py') self.flakes('__path__', filename='package/__init__.py')
def test_globalImportStar(self): def test_globalImportStar(self):
'''Can't find undefined names with import *''' '''Can't find undefined names with import *'''
self.flakes('from fu import *; bar', m.ImportStarUsed) self.flakes('from fu import *; bar', m.ImportStarUsed)
def test_localImportStar(self): def test_localImportStar(self):
'''A local import * still allows undefined names to be found in upper scopes''' '''
A local import * still allows undefined names to be found
in upper scopes
'''
self.flakes(''' self.flakes('''
def a(): def a():
from fu import * from fu import *
@ -80,7 +77,10 @@ class Test(harness.Test):
''') ''')
def test_definedByGlobal(self): def test_definedByGlobal(self):
'''"global" can make an otherwise undefined name in another function defined''' '''
"global" can make an otherwise undefined name
in another function defined
'''
self.flakes(''' self.flakes('''
def a(): global fu; fu = 1 def a(): global fu; fu = 1
def b(): fu def b(): fu
@ -153,13 +153,12 @@ class Test(harness.Test):
return a return a
''', m.UndefinedLocal) ''', m.UndefinedLocal)
def test_intermediateClassScopeIgnored(self): def test_intermediateClassScopeIgnored(self):
""" """
If a name defined in an enclosing scope is shadowed by a local variable If a name defined in an enclosing scope is shadowed by a local variable
and the name is used locally before it is bound, an unbound local and the name is used locally before it is bound, an unbound local
warning is emitted, even if there is a class scope between the enclosing warning is emitted, even if there is a class scope between
scope and the local scope. the enclosing scope and the local scope.
""" """
self.flakes(''' self.flakes('''
def f(): def f():
@ -172,7 +171,6 @@ class Test(harness.Test):
print x print x
''', m.UndefinedLocal) ''', m.UndefinedLocal)
def test_doubleNestingReportsClosestName(self): def test_doubleNestingReportsClosestName(self):
""" """
Test that referencing a local name in a nested scope that shadows a Test that referencing a local name in a nested scope that shadows a
@ -194,7 +192,6 @@ class Test(harness.Test):
''', m.UndefinedLocal).messages[0] ''', m.UndefinedLocal).messages[0]
self.assertEqual(exc.message_args, ('x', 5)) self.assertEqual(exc.message_args, ('x', 5))
def test_laterRedefinedGlobalFromNestedScope3(self): def test_laterRedefinedGlobalFromNestedScope3(self):
""" """
Test that referencing a local name in a nested scope that shadows a Test that referencing a local name in a nested scope that shadows a
@ -249,15 +246,14 @@ class Test(harness.Test):
self.flakes('(a for a in xrange(10) if a)') self.flakes('(a for a in xrange(10) if a)')
class NameTests(TestCase): class NameTests(TestCase):
""" """
Tests for some extra cases of name handling. Tests for some extra cases of name handling.
""" """
def test_impossibleContext(self): def test_impossibleContext(self):
""" """
A Name node with an unrecognized context results in a RuntimeError being A Name node with an unrecognized context results in a RuntimeError
raised. being raised.
""" """
tree = compile("x = 10", "<test>", "exec", PyCF_ONLY_AST) tree = compile("x = 10", "<test>", "exec", PyCF_ONLY_AST)
# Make it into something unrecognizable. # Make it into something unrecognizable.