def test_cast_attribute(self): source = ("from typing import TYPE_CHECKING\n" "if TYPE_CHECKING:\n" " from PyQt5 import QtWebKit\n" "\n" "HistoryType = cast('QtWebKit.QWebHistory', return_value)\n" "\n") expected_names = [ Name(lineno=2, name="TYPE_CHECKING"), Name(lineno=5, name="HistoryType"), Name(lineno=5, name="QtWebKit.QWebHistory"), Name(lineno=5, name="cast"), Name(lineno=5, name="return_value"), ] expected_imports = [ ImportFrom( lineno=1, column=1, name="TYPE_CHECKING", star=False, suggestions=[], ), ImportFrom(lineno=3, column=1, name="QtWebKit", star=False, suggestions=[]), ] self.assertUnimportEqual(source, expected_names, expected_imports)
def test_type_comments(self): source = ( "from typing import Any\n" "from typing import Tuple\n" "from typing import Union\n" "def function(a, b):\n" " # type: (Any, str) -> Union[Tuple[None, None], Tuple[str, str]]\n" " pass\n" ) expected_names = [ Name(lineno=1, name="Any"), Name(lineno=1, name="Union"), Name(lineno=1, name="Tuple"), Name(lineno=1, name="Tuple"), ] expected_classes = [] expected_functions = [Name(4, "function")] expected_imports = [ ImportFrom( lineno=1, name="Any", star=False, module=typing, modules=[] ), ImportFrom( lineno=2, name="Tuple", star=False, module=typing, modules=[], ), ImportFrom( lineno=3, name="Union", star=False, module=typing, modules=[] ), ] self.assertUnimportEqual( source, expected_names, expected_classes, expected_functions, expected_imports, )
def test_union_import(self): source = ( "import typing\n" "if typing.TYPE_CHECKING:\n" " from PyQt5.QtWebEngineWidgets import QWebEngineHistory\n" " from PyQt5.QtWebKit import QWebHistory\n" "\n" "HistoryType = typing.Union['QWebEngineHistory', 'QWebHistory']\n" "\n") expected_names = [ Name(lineno=2, name="typing.TYPE_CHECKING"), Name(lineno=6, name="HistoryType"), Name(lineno=6, name="QWebEngineHistory"), Name(lineno=6, name="QWebHistory"), Name(lineno=6, name="typing.Union"), ] expected_imports = [ Import(lineno=1, column=1, name="typing"), ImportFrom( lineno=3, column=1, name="QWebEngineHistory", star=False, suggestions=[], ), ImportFrom( lineno=4, column=1, name="QWebHistory", star=False, suggestions=[], ), ] self.assertUnimportEqual(source, expected_names, expected_imports)
def test_full_unused(self): source = ( "from x import y\n" "from x import y\n" "from t import x\n" "import re\n" "import ll\n" "import ll\n" "from c import e\n" "import e\n" ) expected_unused_imports = [ ImportFrom( lineno=1, column=1, suggestions=[], name="y", star=False ), ImportFrom( lineno=2, column=1, suggestions=[], name="y", star=False ), ImportFrom( lineno=3, column=1, suggestions=[], name="x", star=False ), Import(lineno=4, column=1, name="re"), Import(lineno=5, column=1, name="ll"), Import(lineno=6, column=1, name="ll"), ImportFrom( lineno=7, column=1, suggestions=[], name="e", star=False ), Import(lineno=8, column=1, name="e"), ] self.assertUnimportEqual(source, expected_unused_imports)
def test_used_and_unused(self): self.assertSourceAfterScanningEqualToExpected( """\ from lib2to3.fixer_util import * from lib2to3.pytree import * from lib2to3.pgen2 import token BlankLine, FromImport, Leaf, Newline, Node token.NAME, token.STAR """, [ ImportFrom( lineno=1, column=1, name="lib2to3.fixer_util", package="lib2to3.fixer_util", star=True, suggestions=[ "BlankLine", "FromImport", "Leaf", # "Newline", "Node", # "token", # ], ), ImportFrom( lineno=2, column=1, name="lib2to3.pytree", package="lib2to3.pytree", star=True, suggestions=["Leaf", "Node"], ), ], )
def test_import_in_function_used_two_different(self): source = ( "import t\n" "print(t)\n\n" "from l import t\n" "from x import y, z, t\n\n" "def function(f=t):\n" " import x\n" " return f\n" "from i import t, ii\n" "print(t)\n" ) expected_unused_imports = [ ImportFrom( lineno=4, column=1, name="t", star=False, suggestions=[] ), ImportFrom( lineno=5, column=1, name="y", star=False, suggestions=[] ), ImportFrom( lineno=5, column=2, name="z", star=False, suggestions=[] ), Import( lineno=8, column=1, name="x", ), ImportFrom( lineno=10, column=2, name="ii", star=False, suggestions=[] ), ] self.assertUnimportEqual(source, expected_unused_imports)
def test_different_duplicate_unused(self): self.assertSourceAfterScanningEqualToExpected( """\ from x import z from y import z """, [ ImportFrom( lineno=1, column=1, suggestions=[], name="z", package="x", star=False, ), ImportFrom( lineno=2, column=1, suggestions=[], name="z", package="y", star=False, ), ], )
def test_used_and_unused(self): source = ("from lib2to3.fixer_util import *\n" "from lib2to3.pytree import *\n" "from lib2to3.pgen2 import token\n" "BlankLine, FromImport, Leaf, Newline, Node\n" "token.NAME, token.STAR\n") expected_unused_imports = [ ImportFrom( lineno=1, module=lib2to3.fixer_util, name="lib2to3.fixer_util", star=True, modules=[ "BlankLine", "FromImport", "Leaf", # "Newline", "Node", # "token", # ], ), ImportFrom( lineno=2, module=lib2to3.pytree, name="lib2to3.pytree", star=True, modules=["Leaf", "Node"], ), ] self.assertUnimportEqual(source, expected_unused_imports)
def test_two_multi_duplicate_one_used(self): source = ( "import t\n" "from l import t\n" "from x import y, z, t\n" "from i import t, ii\n" "print(t)\n" ) expected_unused_imports = [ Import( lineno=1, column=1, name="t", ), ImportFrom( lineno=2, column=1, name="t", star=False, suggestions=[] ), ImportFrom( lineno=3, column=1, name="y", star=False, suggestions=[] ), ImportFrom( lineno=3, column=2, name="z", star=False, suggestions=[] ), ImportFrom( lineno=3, column=3, name="t", star=False, suggestions=[] ), ImportFrom( lineno=4, column=2, name="ii", star=False, suggestions=[] ), ] self.assertUnimportEqual(source, expected_unused_imports)
def test_import_in_function(self): self.assertSourceAfterScanningEqualToExpected( """\ import t from l import t from x import y, z, t def function(f=t): import x return f from i import t, ii print(t) """, [ Import( lineno=1, column=1, name="t", package="t", ), ImportFrom( lineno=2, column=1, name="t", package="l", star=False, suggestions=[], ), ImportFrom( lineno=3, column=1, name="y", package="x", star=False, suggestions=[], ), ImportFrom( lineno=3, column=2, name="z", package="x", star=False, suggestions=[], ), Import( lineno=6, column=1, name="x", package="x", ), ImportFrom( lineno=8, column=2, name="ii", package="i", star=False, suggestions=[], ), ], )
def test_comma(self): self.assertSourceAfterScanningEqualToExpected( """\ from os import ( waitpid, scandir, ) """, [ ImportFrom( lineno=1, column=1, suggestions=[], name="waitpid", package="os", star=False, ), ImportFrom( lineno=1, column=2, suggestions=[], name="scandir", package="os", star=False, ), ], )
def test_three_used(self): source = ("from x import y\n" "from x import y\n" "from t import x\n" "import re\n" "import ll\n" "import ll\n" "from c import e\n" "import e\n" "from pathlib import Path\n" "from pathlib import Path\n" "p = Path()\n" "print(ll)\n" "def function(e=e):pass\n") expected_unused_imports = [ ImportFrom(lineno=1, name="y", star=False, module=None, modules=[]), ImportFrom(lineno=2, name="y", star=False, module=None, modules=[]), ImportFrom(lineno=3, name="x", star=False, module=None, modules=[]), Import(lineno=4, name="re", module=re), Import(lineno=5, name="ll", module=None), ImportFrom(lineno=7, name="e", star=False, module=None, modules=[]), ImportFrom(lineno=9, name="Path", star=False, module=pathlib, modules=[]), ] self.assertUnimportEqual(source, expected_unused_imports)
def test_import_in_function(self): source = ("import t\n" "from l import t\n" "from x import y, z, t\n\n" "def function(f=t):\n" " import x\n" " return f\n" "from i import t, ii\n" "print(t)\n") expected_unused_imports = [ Import(lineno=1, name="t", module=None), ImportFrom(lineno=2, name="t", star=False, module=None, modules=[]), ImportFrom(lineno=3, name="y", star=False, module=None, modules=[]), ImportFrom(lineno=3, name="z", star=False, module=None, modules=[]), Import(lineno=6, name="x", module=None), ImportFrom(lineno=8, name="ii", star=False, module=None, modules=[]), ] self.assertUnimportEqual(source, expected_unused_imports)
def test_two_multi_duplicate_one_used(self): self.assertSourceAfterScanningEqualToExpected( """\ import t from l import t from x import y, z, t from i import t, ii print(t) """, [ Import( lineno=1, column=1, name="t", package="t", ), ImportFrom( lineno=2, column=1, name="t", package="l", star=False, suggestions=[], ), ImportFrom( lineno=3, column=1, name="y", package="x", star=False, suggestions=[], ), ImportFrom( lineno=3, column=2, name="z", package="x", star=False, suggestions=[], ), ImportFrom( lineno=3, column=3, name="t", package="x", star=False, suggestions=[], ), ImportFrom( lineno=4, column=2, name="ii", package="i", star=False, suggestions=[], ), ], )
def test_different_duplicate_unused(self): source = "from x import z\n" "from y import z\n" expected_unused_imports = [ ImportFrom(lineno=1, module=None, modules=[], name="z", star=False), ImportFrom(lineno=2, module=None, modules=[], name="z", star=False), ] self.assertUnimportEqual(source, expected_unused_imports)
def test_comma(self): source = "from os import (\n" " waitpid,\n" " scandir,\n" ")\n" expected_unused_imports = [ ImportFrom( lineno=1, column=1, suggestions=[], name="waitpid", star=False ), ImportFrom( lineno=1, column=2, suggestions=[], name="scandir", star=False ), ] self.assertUnimportEqual(source, expected_unused_imports)
def test_union_attribute(self): self.assertUnimportEqual( source="""\ from typing import TYPE_CHECKING, Union if TYPE_CHECKING: from PyQt5 import QtWebEngineWidgets from PyQt5 import QtWebKit HistoryType = Union['QtWebEngineWidgets.QWebEngineHistory', 'QtWebKit.QWebHistory'] """, expected_names=[ Name(lineno=2, name="TYPE_CHECKING"), Name(lineno=6, name="HistoryType"), Name(lineno=6, name="QtWebEngineWidgets.QWebEngineHistory"), Name(lineno=6, name="QtWebKit.QWebHistory"), Name(lineno=6, name="Union"), ], expected_imports=[ ImportFrom( lineno=1, column=1, name="TYPE_CHECKING", package="typing", star=False, suggestions=[], ), ImportFrom( lineno=1, column=2, name="Union", package="typing", star=False, suggestions=[], ), ImportFrom( lineno=3, column=1, name="QtWebEngineWidgets", package="PyQt5", star=False, suggestions=[], ), ImportFrom( lineno=4, column=1, name="QtWebKit", package="PyQt5", star=False, suggestions=[], ), ], )
def test_used_and_unused(self): self.assertUnimportEqual( """\ from lib2to3.fixer_util import * from lib2to3.pytree import * from lib2to3.pgen2 import token BlankLine, FromImport, Leaf, Newline, Node token.NAME, token.STAR """, expected_names=[ Name(lineno=4, name="BlankLine"), Name(lineno=4, name="FromImport"), Name(lineno=4, name="Leaf"), Name(lineno=4, name="Newline"), Name(lineno=4, name="Node"), Name(lineno=5, name="token.NAME"), Name(lineno=5, name="token.STAR"), ], expected_imports=[ ImportFrom( lineno=1, column=1, name="lib2to3.fixer_util", package="lib2to3.fixer_util", star=True, suggestions=[ "BlankLine", "FromImport", "Leaf", "Newline", "Node", "token", ], ), ImportFrom( lineno=2, column=1, name="lib2to3.pytree", package="lib2to3.pytree", star=True, suggestions=["Leaf", "Node"], ), ImportFrom( lineno=3, column=1, name="token", package="lib2to3.pgen2", star=False, suggestions=[], ), ], )
def test_full_unused(self): self.assertSourceAfterScanningEqualToExpected( """\ from x import y from x import y from t import x import re import ll import ll from c import e import e """, [ ImportFrom( lineno=1, column=1, suggestions=[], name="y", package="x", star=False, ), ImportFrom( lineno=2, column=1, suggestions=[], name="y", package="x", star=False, ), ImportFrom( lineno=3, column=1, suggestions=[], name="x", package="t", star=False, ), Import(lineno=4, column=1, name="re", package="re"), Import(lineno=5, column=1, name="ll", package="ll"), Import(lineno=6, column=1, name="ll", package="ll"), ImportFrom( lineno=7, column=1, suggestions=[], name="e", package="c", star=False, ), Import(lineno=8, column=1, name="e", package="e"), ], )
def test_multi_duplicate(self): source = "from x import y, z, t\n" "import t\n" "from l import t\n" expected_unused_imports = [ ImportFrom(lineno=1, name="y", star=False, module=None, modules=[]), ImportFrom(lineno=1, name="z", star=False, module=None, modules=[]), ImportFrom(lineno=1, name="t", star=False, module=None, modules=[]), Import(lineno=2, name="t", module=None), ImportFrom(lineno=3, name="t", star=False, module=None, modules=[]), ] self.assertUnimportEqual(source, expected_unused_imports)
def test_multi_duplicate(self): self.assertSourceAfterScanningEqualToExpected( """\ from x import y, z, t import t from l import t """, [ ImportFrom( lineno=1, column=1, name="y", package="x", star=False, suggestions=[], ), ImportFrom( lineno=1, column=2, name="z", package="x", star=False, suggestions=[], ), ImportFrom( lineno=1, column=3, name="t", package="x", star=False, suggestions=[], ), Import( lineno=2, column=1, name="t", package="t", ), ImportFrom( lineno=3, column=1, name="t", package="l", star=False, suggestions=[], ), ], )
def visit_ImportFrom(self, node: ast.ImportFrom) -> None: if self.skip_import(node): return is_star = node.names[0].name == "*" for column, alias in enumerate(node.names): if not node.level: package = node.module else: package = "." * node.level alias_name = alias.asname or alias.name if ((package in self.ignore_modules_imports) or (alias_name in self.ignore_alias_imports) or (is_star and not self.include_star_import)): return name = package if is_star else alias_name self.imports.append( ImportFrom( lineno=node.lineno, column=column + 1, name=name, star=is_star, suggestions=[], package=package, )) self.import_names.append(name)
def test_cast_import(self): self.assertUnimportEqual( source="""\ import typing if typing.TYPE_CHECKING: from PyQt5.QtWebKit import QWebHistory HistoryType = typing.cast('QWebHistory', None) """, expected_names=[ Name(lineno=2, name="typing.TYPE_CHECKING"), Name(lineno=5, name="HistoryType"), Name(lineno=5, name="QWebHistory"), Name(lineno=5, name="typing.cast"), ], expected_imports=[ Import( lineno=1, column=1, name="typing", package="typing", ), ImportFrom( lineno=3, column=1, name="QWebHistory", package="PyQt5.QtWebKit", star=False, suggestions=[], ), ], )
def test_defined_class(self): self.assertUnimportEqual( source="""\ __all__ = ["NodeVisitor", "parse"] from ast import * class NodeVisitor: ... literal_eval """, expected_names=[ Name(lineno=1, name="__all__"), Name(lineno=8, name="literal_eval"), Name(lineno=1, name="NodeVisitor", is_all=True), Name(lineno=1, name="parse", is_all=True), ], expected_imports=[ ImportFrom( lineno=3, column=1, name="ast", package="ast", star=True, suggestions=["literal_eval", "parse"], ) ], )
def test_defined_function(self): self.assertUnimportEqual( source="""\ from ast import * __all__.extend(["NodeVisitor", "parse"]) def literal_eval(): ... """, expected_names=[ Name(lineno=3, name="__all__.extend"), Name(lineno=3, name="NodeVisitor", is_all=True), Name(lineno=3, name="parse", is_all=True), ], expected_imports=[ ImportFrom( lineno=1, column=1, name="ast", package="ast", star=True, suggestions=["NodeVisitor", "parse"], ) ], )
def visit_ImportFrom(self, node: ast.ImportFrom) -> None: if self.skip_import(node): return is_star = node.names[0].name == "*" for alias in node.names: package = node.module or alias.name alias_name = alias.asname or alias.name name = package if is_star else alias_name if package in self.ignore_imports or ( is_star and not self.include_star_import ): return module: Optional[ModuleType] try: module = importlib.import_module(package) except BaseException: module = None self.imports.append( ImportFrom( lineno=node.lineno, name=name, star=is_star, module=module, modules=[], ) )
def test_star_unused(self): # in this case this import is unused source = "from os import *\n" "__all__ = ['test']" expected_unused_imports = [ ImportFrom(lineno=1, module=os, modules=[], name="os", star=True), ] self.assertUnimportEqual(source, expected_unused_imports)
def test_plus_bin_op(self): # NOTE no support. source = f"from os import *\n" "__all__ = ['w' + 'alk']" expected_unused_imports = [ ImportFrom(lineno=1, module=os, modules=[], name="os", star=True), ] self.assertUnimportEqual(source, expected_unused_imports)
def test_list_comprehension(self): # NOTE no support. source = ("from os import *\n" "__all__ = [expression for item in ['os', 'walk']]") expected_unused_imports = [ ImportFrom(lineno=1, module=os, modules=[], name="os", star=True), ] self.assertUnimportEqual(source, expected_unused_imports)
def test_type_comments(self): self.assertUnimportEqual( source="""\ from typing import Any from typing import Tuple from typing import Union def function(a, b): # type: (Any, str) -> Union[Tuple[None, None], Tuple[str, str]] pass """, expected_names=[ Name(lineno=4, name="Any"), Name(lineno=4, name="str"), Name(lineno=4, name="Union"), Name(lineno=4, name="Tuple"), Name(lineno=4, name="Tuple"), Name(lineno=4, name="str"), Name(lineno=4, name="str"), ], expected_imports=[ ImportFrom( lineno=1, column=1, name="Any", package="typing", star=False, suggestions=[], ), ImportFrom( lineno=2, column=1, name="Tuple", package="typing", star=False, suggestions=[], ), ImportFrom( lineno=3, column=1, name="Union", package="typing", star=False, suggestions=[], ), ], )