コード例 #1
0
def show(
    unused_import: List[Union[Import, ImportFrom]], py_path: Path
) -> None:
    for imp in unused_import:
        context = ""
        if (
            isinstance(imp, ImportFrom)
            and imp.star
            and imp.module
            and imp.modules
        ):
            context = (
                Color(f"from {imp.name} import *").red
                + " -> "
                + Color(
                    f"from {imp.name} import {', '.join(imp.modules)}"
                ).green
            )
        else:
            context = Color(imp.name).yellow
        print(
            context
            + " at "
            + Color(str(py_path)).green
            + ":"
            + Color(str(imp.lineno)).green
        )
コード例 #2
0
ファイル: scan.py プロジェクト: jackton1/unimport
 def run_visit(self, source: Union[str, bytes], mode: str = "exec") -> None:
     try:
         tree = ast.parse(source, mode=mode)
     except SyntaxError as err:
         print(Color(str(err)).red)
     else:
         Relate(tree)
         self.visit(tree)
コード例 #3
0
 def read(self, path: Path) -> Tuple[str, str]:
     try:
         with tokenize.open(path) as stream:
             source = stream.read()
             encoding = stream.encoding
     except (OSError, SyntaxError) as err:
         if self.show_error:
             print(Color(str(err)).red)
         return "", "utf-8"
     return source, encoding
コード例 #4
0
def refactor_string(source, unused_imports):
    try:
        wrapper = MetadataWrapper(cst.parse_module(source))
    except cst.ParserSyntaxError as err:
        print(Color(str(err)).red)
    else:
        if unused_imports:
            fixed_module = wrapper.visit(
                RemoveUnusedImportTransformer(unused_imports))
            return fixed_module.code
    return source
コード例 #5
0
ファイル: __main__.py プロジェクト: semakaratas/unimport
def main(argv=None):
    namespace = parser.parse_args(argv)
    namespace.check = namespace.check or not any(
        [value for key, value in vars(namespace).items()][5:-1])
    session = Session(
        config_file=namespace.config,
        include_star_import=namespace.include_star_import,
    )
    include_list, exclude_list = [], []
    if namespace.include:
        include_list.append(namespace.include)
    if hasattr(session.config, "include"):
        include_list.append(session.config.include or "")
    if namespace.exclude:
        exclude_list.append(namespace.exclude)
    if hasattr(session.config, "exclude"):
        exclude_list.append(session.config.exclude or "")
    include = re.compile("|".join(include_list)).pattern
    exclude = re.compile("|".join(exclude_list)).pattern
    _any_unimport = False
    for source_path in namespace.sources:
        for py_path in session._list_paths(source_path, include, exclude):
            if namespace.check:
                session.scanner.run_visit(source=session._read(py_path)[0])
                unused_imports = list(session.scanner.get_unused_imports())
                show(unused_imports, py_path)
                if not (not _any_unimport and not unused_imports):
                    _any_unimport = True
                session.scanner.clear()
            if namespace.diff or namespace.permission:
                exists_diff = print_if_exists(session.diff_file(py_path))
            if namespace.permission and exists_diff:
                action = input(
                    f"Apply suggested changes to '{Color(str(py_path)).yellow}' [Y/n/q] ? >"
                ).lower()
                if action == "q":
                    break
                elif action == "y" or action == "":
                    namespace.remove = True
            if namespace.remove:
                source = session._read(py_path)[0]
                refactor_source = session.refactor_file(py_path, apply=True)
                if refactor_source != source:
                    print(f"Refactoring '{Color(str(py_path)).green}'")
    if not _any_unimport and namespace.check:
        print(
            Color(
                "✨ Congratulations there is no unused import in your project. ✨"
            ).green)
コード例 #6
0
def color_diff(sequence: Tuple[str, ...]) -> str:
    contents = "\n".join(sequence)
    lines = contents.split("\n")
    for i, line in enumerate(lines):
        paint = Color(line)
        if line.startswith("+++") or line.startswith("---"):
            line = paint.bold_white
        if line.startswith("@@"):
            line = paint.cyan
        if line.startswith("+"):
            line = paint.green
        elif line.startswith("-"):
            line = paint.red
        lines[i] = line
    return "\n".join(lines)
コード例 #7
0
ファイル: refactor.py プロジェクト: 5l1v3r1/unimport
def refactor_string(
    source: str,
    unused_imports: "List[TYPE_IMPORT]",
    show_error: bool,
) -> str:
    try:
        wrapper = MetadataWrapper(cst.parse_module(source))
    except cst.ParserSyntaxError as err:
        if show_error:
            print(Color(str(err)).red)
    else:
        if unused_imports:
            fixed_module = wrapper.visit(
                RemoveUnusedImportTransformer(unused_imports))
            return fixed_module.code
    return source
コード例 #8
0
def main(argv: Optional[List[str]] = None) -> None:
    namespace = parser.parse_args(argv)
    namespace.check = namespace.check or not any(
        [namespace.diff, namespace.remove, namespace.permission]
    )
    namespace.diff = namespace.diff or namespace.permission
    session = Session(
        config_file=namespace.config,
        include_star_import=namespace.include_star_import,
        show_error=namespace.show_error,
    )
    include_list = []
    exclude_list = []
    if namespace.include:
        include_list.append(namespace.include)
    if hasattr(session.config, "include"):
        include_list.append(session.config.include)  # type: ignore
    if namespace.exclude:
        exclude_list.append(namespace.exclude)
    if hasattr(session.config, "exclude"):
        exclude_list.append(session.config.exclude)  # type: ignore
    include = re.compile("|".join(include_list)).pattern
    exclude = re.compile("|".join(exclude_list)).pattern
    is_unused_module = False
    unused_modules = set()
    for source_path in namespace.sources:
        for py_path in session.list_paths(source_path, include, exclude):
            session.scanner.scan(source=session.read(py_path)[0])
            unused_imports = session.scanner.unused_imports
            if not is_unused_module and unused_imports:
                is_unused_module = True
            if unused_imports:
                unused_modules.update(
                    {
                        imp.module.__name__.split(".")[0]  # type: ignore
                        for imp in unused_imports
                        if imp.module
                    }
                )
            if namespace.check:
                show(unused_imports, py_path)
            session.scanner.clear()
            if namespace.diff:
                exists_diff = print_if_exists(session.diff_file(py_path))
            if namespace.permission and exists_diff:
                action = input(
                    f"Apply suggested changes to '{Color(str(py_path)).yellow}' [Y/n/q] ? >"
                ).lower()
                if action == "q":
                    return
                elif action == "y" or action == "":
                    namespace.remove = True
            if namespace.remove:
                source = session.read(py_path)[0]
                refactor_source = session.refactor_file(py_path, apply=True)
                if refactor_source != source:
                    print(f"Refactoring '{Color(str(py_path)).green}'")
    if not is_unused_module and namespace.check:
        print(
            Color(
                "✨ Congratulations there is no unused import in your project. ✨"
            ).green
        )
    if namespace.requirements and unused_modules:
        requirements_path = Path("requirements.txt")
        if not requirements_path.exists():
            return
        result = ""
        source = requirements_path.read_text()
        for index, requirement in enumerate(source.splitlines()):
            if requirement.split("==")[0] not in unused_modules:
                result += f"{requirement}\n"
            else:
                if namespace.check and requirement:
                    print(
                        f"{Color(requirement).cyan} at "
                        f"{Color(str(requirements_path)).cyan}:{Color(str(index + 1)).cyan}"
                    )
        if namespace.diff:
            exists_diff = print_if_exists(
                tuple(
                    difflib.unified_diff(
                        source.splitlines(),
                        result.splitlines(),
                        fromfile=str(requirements_path),
                    )
                )
            )
        if namespace.permission and exists_diff:
            action = input(
                f"Apply suggested changes to '{Color(str(requirements_path)).cyan}' [Y/n] ? >"
            ).lower()
            if action == "y" or action == "":
                namespace.remove = True
        if namespace.remove:
            requirements_path.write_text(result)
            print(f"Refactoring '{Color(str(requirements_path)).cyan}'")
コード例 #9
0
ファイル: __main__.py プロジェクト: jackton1/unimport
def main(argv: Optional[List[str]] = None) -> int:
    argv = argv if argv is not None else sys.argv[1:]
    parser = argparse.ArgumentParser(
        prog="unimport",
        description=C.DESCRIPTION,
        epilog="Get rid of all unused imports 🥳",
    )
    exclusive_group = parser.add_mutually_exclusive_group(required=False)
    parser.add_argument(
        "sources",
        default=[Path(".")],
        nargs="*",
        help="files and folders to find the unused imports.",
        action="store",
        type=Path,
    )
    parser.add_argument(
        "-c",
        "--config",
        default=".",
        help="read configuration from PATH.",
        metavar="PATH",
        action="store",
        type=Path,
    )
    parser.add_argument(
        "--include",
        help="file include pattern.",
        metavar="include",
        action="store",
        default="",
        type=str,
    )
    parser.add_argument(
        "--exclude",
        help="file exclude pattern.",
        metavar="exclude",
        action="store",
        default="",
        type=str,
    )
    parser.add_argument(
        "--include-star-import",
        action="store_true",
        help="Include star imports during scanning and refactor.",
    )
    parser.add_argument(
        "--show-error",
        action="store_true",
        help="Show or don't show errors captured during static analysis.",
    )
    parser.add_argument(
        "-d",
        "--diff",
        action="store_true",
        help="Prints a diff of all the changes unimport would make to a file.",
    )
    exclusive_group.add_argument(
        "-r",
        "--remove",
        action="store_true",
        help="remove unused imports automatically.",
    )
    exclusive_group.add_argument(
        "-p",
        "--permission",
        action="store_true",
        help="Refactor permission after see diff.",
    )
    parser.add_argument(
        "--requirements",
        action="store_true",
        help=
        "Include requirements.txt file, You can use it with all other arguments",
    )
    parser.add_argument(
        "--check",
        action="store_true",
        help="Prints which file the unused imports are in.",
    )
    parser.add_argument(
        "-v",
        "--version",
        action="version",
        version=f"Unimport {C.VERSION}",
        help="Prints version of unimport",
    )

    namespace = parser.parse_args(argv)
    namespace.check = namespace.check or not any(
        [namespace.diff, namespace.remove, namespace.permission])
    namespace.diff = namespace.diff or namespace.permission
    session = Session(
        config_file=namespace.config,
        include_star_import=namespace.include_star_import,
        show_error=namespace.show_error,
    )
    include_list = []
    exclude_list = []
    if namespace.include:
        include_list.append(namespace.include)
    if hasattr(session.config, "include"):
        include_list.append(session.config.include)  # type: ignore
    if namespace.exclude:
        exclude_list.append(namespace.exclude)
    if hasattr(session.config, "exclude"):
        exclude_list.append(session.config.exclude)  # type: ignore
    include = re.compile("|".join(include_list)).pattern
    exclude = re.compile("|".join(exclude_list)).pattern
    unused_modules = set()
    for source_path in namespace.sources:
        for py_path in session.list_paths(source_path, include, exclude):
            session.scanner.scan(source=session.read(py_path)[0])
            unused_imports = session.scanner.unused_imports
            if unused_imports:
                unused_modules.update({
                    imp.module.__name__.split(".")[0]  # type: ignore
                    for imp in unused_imports if imp.module
                })
            if namespace.check:
                show(unused_imports, py_path)
            session.scanner.clear()
            if namespace.diff:
                exists_diff = print_if_exists(session.diff_file(py_path))
            if namespace.permission and exists_diff:
                action = input(
                    f"Apply suggested changes to '{Color(str(py_path)).yellow}' [Y/n/q] ? >"
                ).lower()
                if action == "q":
                    return 1
                elif action == "y" or action == "":
                    namespace.remove = True
            if namespace.remove:
                source = session.read(py_path)[0]
                refactor_source = session.refactor_file(py_path, apply=True)
                if refactor_source != source:
                    print(f"Refactoring '{Color(str(py_path)).green}'")
    if not unused_modules and namespace.check:
        print(
            Color(
                "✨ Congratulations there is no unused import in your project. ✨"
            ).green)
    requirements_path = Path("requirements.txt")
    if (namespace.requirements and unused_modules
            and requirements_path.exists()):
        result = ""
        source = requirements_path.read_text()
        for index, requirement in enumerate(source.splitlines()):
            if requirement.split("==")[0] not in unused_modules:
                result += f"{requirement}\n"
            else:
                if namespace.check and requirement:
                    print(
                        f"{Color(requirement).cyan} at "
                        f"{Color(str(requirements_path)).cyan}:{Color(str(index + 1)).cyan}"
                    )
        if namespace.diff:
            exists_diff = print_if_exists(
                tuple(
                    difflib.unified_diff(
                        source.splitlines(),
                        result.splitlines(),
                        fromfile=str(requirements_path),
                    )))
        if namespace.permission and exists_diff:
            action = input(
                f"Apply suggested changes to '{Color(str(requirements_path)).cyan}' [Y/n] ? >"
            ).lower()
            if action == "y" or action == "":
                namespace.remove = True
        if namespace.remove:
            requirements_path.write_text(result)
            print(f"Refactoring '{Color(str(requirements_path)).cyan}'")
    if unused_modules:
        return 1
    else:
        return 0