from __future__ import absolute_import, division, print_function, unicode_literals from sys import version_info import pytest from pies.overrides import * from frosted import messages as m from .utils import flakes def test_unusedImport(): flakes('import fu, bar', m.UnusedImport, m.UnusedImport) flakes('from baz import fu, bar', m.UnusedImport, m.UnusedImport) def test_aliasedImport(): flakes('import fu as FU, bar as FU', m.RedefinedWhileUnused, m.UnusedImport) flakes('from moo import fu as FU, bar as FU', m.RedefinedWhileUnused, m.UnusedImport) def test_usedImport(): flakes('import fu; print(fu)') flakes('from baz import fu; print(fu)') flakes('import fu; del fu') def test_redefinedWhileUnused(): flakes('import fu; fu = 3', m.RedefinedWhileUnused) flakes('import fu; fu, bar = 3', m.RedefinedWhileUnused) flakes('import fu; [fu, bar] = 3', m.RedefinedWhileUnused) def test_redefinedIf(): """Test that importing a module twice within an if block does raise a warning.""" flakes(''' i = 2 if i==1: import os import os os.path''', m.RedefinedWhileUnused) def test_redefinedIfElse(): """Test that importing a module twice in if and else blocks does not raise a warning.""" flakes(''' i = 2 if i==1: import os else: import os os.path''') def test_redefinedTry(): """Test that importing a module twice in an try block does raise a warning.""" flakes(''' try: import os import os except Exception: pass os.path''', m.RedefinedWhileUnused) def test_redefinedTryExcept(): """Test that importing a module twice in an try and except block does not raise a warning.""" flakes(''' try: import os except Exception: import os os.path''') def test_redefinedTryNested(): """Test that importing a module twice using a nested try/except and if blocks does not issue a warning.""" flakes(''' try: if True: if True: import os except Exception: import os os.path''') def test_redefinedTryExceptMulti(): flakes(""" try: from aa import mixer except AttributeError: from bb import mixer except RuntimeError: from cc import mixer except Exception: from dd import mixer mixer(123) """) def test_redefinedTryElse(): flakes(""" try: from aa import mixer except ImportError: pass else: from bb import mixer mixer(123) """, m.RedefinedWhileUnused) def test_redefinedTryExceptElse(): flakes(""" try: import funca except ImportError: from bb import funca from bb import funcb else: from bbb import funcb print(funca, funcb) """) def test_redefinedTryExceptFinally(): flakes(""" try: from aa import a except ImportError: from bb import a finally: a = 42 print(a) """) def test_redefinedTryExceptElseFinally(): flakes(""" try: import b except ImportError: b = Ellipsis from bb import a else: from aa import a finally: a = 42 print(a, b) """) def test_redefinedByFunction(): flakes(''' import fu def fu(): pass ''', m.RedefinedWhileUnused) def test_redefinedInNestedFunction(): """Test that shadowing a global name with a nested function definition generates a warning.""" flakes(''' import fu def bar(): def baz(): def fu(): pass ''', m.RedefinedWhileUnused, m.UnusedImport) def test_redefinedByClass(): flakes(''' import fu class fu: pass ''', m.RedefinedWhileUnused) def test_redefinedBySubclass(): """If an imported name is redefined by a class statement which also uses that name in the bases list, no warning is emitted. """ flakes(''' from fu import bar class bar(bar): pass ''') def test_redefinedInClass(): """Test that shadowing a global with a class attribute does not produce a warning.""" flakes(''' import fu class bar: fu = 1 print(fu) ''') def test_usedInFunction(): flakes(''' import fu def fun(): print(fu) ''') def test_shadowedByParameter(): flakes(''' import fu def fun(fu): print(fu) ''', m.UnusedImport) flakes(''' import fu def fun(fu): print(fu) print(fu) ''') def test_newAssignment(): flakes('fu = None') def test_usedInGetattr(): flakes('import fu; fu.bar.baz') flakes('import fu; "bar".fu.baz', m.UnusedImport) def test_usedInSlice(): flakes('import fu; print(fu.bar[1:])') def test_usedInIfBody(): flakes(''' import fu if True: print(fu) ''') def test_usedInIfConditional(): flakes(''' import fu if fu: pass ''') def test_usedInElifConditional(): flakes(''' import fu if False: pass elif fu: pass ''') def test_usedInElse(): flakes(''' import fu if False: pass else: print(fu) ''') def test_usedInCall(): flakes('import fu; fu.bar()') def test_usedInClass(): flakes(''' import fu class bar: bar = fu ''') def test_usedInClassBase(): flakes(''' import fu class bar(object, fu.baz): pass ''') def test_notUsedInNestedScope(): flakes(''' import fu def bleh(): pass print(fu) ''') def test_usedInFor(): flakes(''' import fu for bar in range(9): print(fu) ''') def test_usedInForElse(): flakes(''' import fu for bar in range(10): pass else: print(fu) ''') def test_redefinedByFor(): flakes(''' import fu for fu in range(2): pass ''', m.RedefinedWhileUnused) def test_shadowedByFor(): """Test that shadowing a global name with a for loop variable generates a warning.""" flakes(''' import fu fu.bar() for fu in (): pass ''', m.ImportShadowedByLoopVar) def test_shadowedByForDeep(): """Test that shadowing a global name with a for loop variable nested in a tuple unpack generates a warning.""" flakes(''' import fu fu.bar() for (x, y, z, (a, b, c, (fu,))) in (): pass ''', m.ImportShadowedByLoopVar) def test_usedInReturn(): flakes(''' import fu def fun(): return fu ''') def test_usedInOperators(): flakes('import fu; 3 + fu.bar') flakes('import fu; 3 % fu.bar') flakes('import fu; 3 - fu.bar') flakes('import fu; 3 * fu.bar') flakes('import fu; 3 ** fu.bar') flakes('import fu; 3 / fu.bar') flakes('import fu; 3 // fu.bar') flakes('import fu; -fu.bar') flakes('import fu; ~fu.bar') flakes('import fu; 1 == fu.bar') flakes('import fu; 1 | fu.bar') flakes('import fu; 1 & fu.bar') flakes('import fu; 1 ^ fu.bar') flakes('import fu; 1 >> fu.bar') flakes('import fu; 1 << fu.bar') def test_usedInAssert(): flakes('import fu; assert fu.bar') def test_usedInSubscript(): flakes('import fu; fu.bar[1]') def test_usedInLogic(): flakes('import fu; fu and False') flakes('import fu; fu or False') flakes('import fu; not fu.bar') def test_usedInList(): flakes('import fu; [fu]') def test_usedInTuple(): flakes('import fu; (fu,)') def test_usedInTry(): flakes(''' import fu try: fu except Exception: pass ''') def test_usedInExcept(): flakes(''' import fu try: fu except Exception: pass ''') def test_redefinedByExcept(): as_exc = ', ' if version_info < (2, 6) else ' as ' flakes(''' import fu try: pass except Exception%sfu: pass ''' % as_exc, m.RedefinedWhileUnused) def test_usedInRaise(): flakes(''' import fu raise fu.bar ''') def test_usedInYield(): flakes(''' import fu def gen(): yield fu ''') def test_usedInDict(): flakes('import fu; {fu:None}') flakes('import fu; {1:fu}') def test_usedInParameterDefault(): flakes(''' import fu def f(bar=fu): pass ''') def test_usedInAttributeAssign(): flakes('import fu; fu.bar = 1') def test_usedInKeywordArg(): flakes('import fu; fu.bar(stuff=fu)') def test_usedInAssignment(): flakes('import fu; bar=fu') flakes('import fu; n=0; n+=fu') def test_usedInListComp(): flakes('import fu; [fu for _ in range(1)]') flakes('import fu; [1 for _ in range(1) if fu]') def test_redefinedByListComp(): flakes('import fu; [1 for fu in range(1)]', m.RedefinedWhileUnused) def test_usedInTryFinally(): flakes(''' import fu try: pass finally: fu ''') flakes(''' import fu try: fu finally: pass ''') def test_usedInWhile(): flakes(''' import fu while 0: fu ''') flakes(''' import fu while fu: pass ''') def test_usedInGlobal(): flakes(''' import fu def f(): global fu ''', m.UnusedImport) @pytest.mark.skipif("version_info >= (3,)") def test_usedInBackquote(): flakes('import fu; `fu`') def test_usedInExec(): if version_info < (3,): exec_stmt = 'exec "print 1" in fu.bar' else: exec_stmt = 'exec("print(1)", fu.bar)' flakes('import fu; %s' % exec_stmt) def test_usedInLambda(): flakes('import fu; lambda: fu') def test_shadowedByLambda(): flakes('import fu; lambda fu: fu', m.UnusedImport) def test_usedInSliceObj(): flakes('import fu; "meow"[::fu]') def test_unusedInNestedScope(): flakes(''' def bar(): import fu fu ''', m.UnusedImport, m.UndefinedName) def test_methodsDontUseClassScope(): flakes(''' class bar: import fu def fun(): fu ''', m.UnusedImport, m.UndefinedName) def test_nestedFunctionsNestScope(): flakes(''' def a(): def b(): fu import fu ''') def test_nestedClassAndFunctionScope(): flakes(''' def a(): import fu class b: def c(): print(fu) ''') def test_importStar(): flakes('from fu import *', m.ImportStarUsed, ignore_frosted_errors=[]) def test_packageImport(): """If a dotted name is imported and used, no warning is reported.""" flakes(''' import fu.bar fu.bar ''') def test_unusedPackageImport(): """If a dotted name is imported and not used, an unused import warning is reported.""" flakes('import fu.bar', m.UnusedImport) def test_duplicateSubmoduleImport(): """If a submodule of a package is imported twice, an unused import warning and a redefined while unused warning are reported. """ flakes(''' import fu.bar, fu.bar fu.bar ''', m.RedefinedWhileUnused) flakes(''' import fu.bar import fu.bar fu.bar ''', m.RedefinedWhileUnused) def test_differentSubmoduleImport(): """If two different submodules of a package are imported, no duplicate import warning is reported for the package. """ flakes(''' import fu.bar, fu.baz fu.bar, fu.baz ''') flakes(''' import fu.bar import fu.baz fu.bar, fu.baz ''') def test_assignRHSFirst(): flakes('import fu; fu = fu') flakes('import fu; fu, bar = fu') flakes('import fu; [fu, bar] = fu') flakes('import fu; fu += fu') def test_tryingMultipleImports(): flakes(''' try: import fu except ImportError: import bar as fu fu ''') def test_nonGlobalDoesNotRedefine(): flakes(''' import fu def a(): fu = 3 return fu fu ''') def test_functionsRunLater(): flakes(''' def a(): fu import fu ''') def test_functionNamesAreBoundNow(): flakes(''' import fu def fu(): fu fu ''', m.RedefinedWhileUnused) def test_ignoreNonImportRedefinitions(): flakes('a = 1; a = 2') @pytest.mark.skipif("'todo'") def test_importingForImportError(): flakes(''' try: import fu except ImportError: pass ''') @pytest.mark.skipif("'todo: requires evaluating attribute access'") def test_importedInClass(): """Imports in class scope can be used through.""" flakes(''' class c: import i def __init__(): i ''') def test_futureImport(): """__future__ is special.""" flakes('from __future__ import division') flakes(''' "docstring is allowed before future import" from __future__ import division ''') def test_futureImportFirst(): """__future__ imports must come before anything else.""" flakes(''' x = 5 from __future__ import division ''', m.LateFutureImport) flakes(''' from foo import bar from __future__ import division bar ''', m.LateFutureImport) def test_ignoredInFunction(): """An C{__all__} definition does not suppress unused import warnings in a function scope.""" flakes(''' def foo(): import bar __all__ = ["bar"] ''', m.UnusedImport, m.UnusedVariable) def test_ignoredInClass(): """An C{__all__} definition does not suppress unused import warnings in a class scope.""" flakes(''' class foo: import bar __all__ = ["bar"] ''', m.UnusedImport) def test_warningSuppressed(): """If a name is imported and unused but is named in C{__all__}, no warning is reported.""" flakes(''' import foo __all__ = ["foo"] ''') def test_unrecognizable(): """If C{__all__} is defined in a way that can't be recognized statically, it is ignored.""" flakes(''' import foo __all__ = ["f" + "oo"] ''', m.UnusedImport) flakes(''' import foo __all__ = [] + ["foo"] ''', m.UnusedImport) def test_unboundExported(): """If C{__all__} includes a name which is not bound, a warning is emitted.""" flakes(''' __all__ = ["foo"] ''', m.UndefinedExport) # Skip this in __init__.py though, since the rules there are a little # different. for filename in ["foo/__init__.py", "__init__.py"]: flakes(''' __all__ = ["foo"] ''', filename=filename, **{'ignore_frosted_errors_for___init__.py': ['E101', 'E103']}) def test_importStarExported(): """Do not report undefined if import * is used""" flakes(''' from foolib import * __all__ = ["foo"] ''', m.ImportStarUsed) def test_usedInGenExp(): """Using a global in a generator expression results in no warnings.""" flakes('import fu; (fu for _ in range(1))') flakes('import fu; (1 for _ in range(1) if fu)') def test_redefinedByGenExp(): """ Re-using a global name as the loop variable for a generator expression results in a redefinition warning. """ flakes('import fu; (1 for fu in range(1))', m.RedefinedWhileUnused, m.UnusedImport) def test_usedAsDecorator(): """Using a global name in a decorator statement results in no warnings, but using an undefined name in a decorator statement results in an undefined name warning. """ flakes(''' from interior import decorate @decorate def f(): return "hello" ''') flakes(''' from interior import decorate @decorate('value') def f(): return "hello" ''') flakes(''' @decorate def f(): return "hello" ''', m.UndefinedName) def test_usedAsClassDecorator(): """Using an imported name as a class decorator results in no warnings but using an undefined name as a class decorator results in an undefined name warning. """ flakes(''' from interior import decorate @decorate class foo: pass ''') flakes(''' from interior import decorate @decorate("foo") class bar: pass ''') flakes(''' @decorate class foo: pass ''', m.UndefinedName)