Skip to content

Commit

Permalink
General API Cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
isidentical committed Jan 12, 2020
1 parent 9147f02 commit f3efe47
Show file tree
Hide file tree
Showing 11 changed files with 199 additions and 212 deletions.
22 changes: 1 addition & 21 deletions README.md
Expand Up @@ -22,26 +22,6 @@ unimport {source_file_or_directory} or write direct unimport to current path sca

[![](https://img.shields.io/badge/style-unimport-green)](https://github.com/hakancelik96/unimport)

### Another alternative
```python
import inspect
import os
from unimport.unused from get_unused

for unused in get_unused(source=inspect.getsource(os)):
print(unused)
```

```python
import tokenize
from unimport.files import get_files
from unimport.unused import get_unused

for path in get_files(direction="."):
for unused in get_unused(source=tokenize.open(path).read()):
print(unused, path)
```

## Configuring Unimport
To configure unimport for a single user create a ~/.unimport.cfg and type the names of folders that you do not want scanning.

Expand Down Expand Up @@ -125,4 +105,4 @@ For example; module: inspect, name; inspect.getsource; result unused import = in
### V0.0.1
- unimport {source_file_or_directory}
- .unimport.cfg 'type the names of files or folders that you do not want to scan.'
- Does not replace files only shows results.
- Does not replace files only shows results.
Empty file removed test.py
Empty file.
14 changes: 5 additions & 9 deletions tests/test_overwrite.py
@@ -1,23 +1,19 @@
import tokenize
from unittest import TestCase

from unimport.auto_refactor import refactor
from unimport.unused import get_unused
from unimport.session import Session

from .test_helper import TEST_DIR


class OverwriteTest(TestCase):
def setUp(self):
self.session = Session()

def test_remove_unused_imports(self):
for py_file in (TEST_DIR / "samples").glob("*_action.py"):
with self.subTest(filename=py_file):
with tokenize.open(py_file) as stream:
source = stream.read()
unused_imports = [
unused_import["name"]
for unused_import in get_unused(source=source)
]
source_action = refactor(source, unused_imports,)
source_action = self.session.refactor_file(py_file)
source_expected = (
py_file.parent
/ f"{py_file.name.rstrip('action.py')}expected.py"
Expand Down
2 changes: 1 addition & 1 deletion unimport/__init__.py
Expand Up @@ -2,6 +2,6 @@
__version__ = "0.1.0"
__author__ = (
"Hakan Çelik <hakancelik96@outlook.com>, "
"Batuhan Taşkaya <>, "
"Batuhan Taşkaya <isidentical@gmail.com>, "
"Gökmen Görgen <>, "
)
68 changes: 68 additions & 0 deletions unimport/__main__.py
@@ -0,0 +1,68 @@
import argparse
import pathlib
import sys

from unimport.session import Session

parser = argparse.ArgumentParser(
description="Detect or remove unused Python imports."
)
parser.add_argument(
"sources",
default=".",
nargs="*",
help="files and folders to find the unused imports.",
type=pathlib.Path,
)
parser.add_argument(
"-c",
"--config",
help="read configuration from PATH.",
metavar="PATH",
type=pathlib.Path,
)
parser.add_argument(
"-w",
"--write",
action="store_true",
help="remove unused imports automatically.",
)
parser.add_argument(
"-d",
"--diff",
action="store_true",
help="Prints a diff of all the changes unimport would make to a file.",
)


def main(argv=None):
namespace = parser.parse_args(argv)
session = Session(config_file=namespace.config)
sources = []
for source in namespace.sources:
sources.extend(session._list_paths(source, "**/*.py"))

if namespace.diff and namespace.write:
for source in sources:
print(*session.diff_file(source), sep="\n")
session.refactor_file(source, apply=True)
elif namespace.diff:
for source in sources:
print(*session.diff_file(source), sep="\n")
action = input(
f"Apply suggested changes to '{source}' [y/n/q] ? > "
)
if action == "q":
break
elif action == "y":
session.refactor_file(source, apply=True)
elif namespace.write:
for source in sources:
session.refactor_file(source, apply=True)
else:
for source in sources:
print(*session.scan_file(source), sep="\n")
print("All done!")

if __name__ == "__main__":
main(sys.argv[1:])
101 changes: 0 additions & 101 deletions unimport/console.py

This file was deleted.

37 changes: 0 additions & 37 deletions unimport/files.py

This file was deleted.

30 changes: 20 additions & 10 deletions unimport/auto_refactor.py → unimport/refactor.py
@@ -1,3 +1,4 @@
from contextlib import contextmanager
from lib2to3.fixer_base import BaseFix
from lib2to3.fixer_util import BlankLine, syms, token
from lib2to3.refactor import RefactoringTool
Expand Down Expand Up @@ -30,10 +31,19 @@ class RefactorImports(BaseFix):
>
"""

def __init__(self, unused_modules):
self.unused_modules = unused_modules
def __init__(self):
self.unused_modules = []
super().__init__(None, None) # options and logger

@contextmanager
def clean(self, unused_modules):
try:
self.unused_modules.clear()
self.unused_modules.extend(unused_modules)
yield
finally:
self.unused_modules.clear()

def transform(self, node, results):
imports = results["imp"]
if node.children[0].type == syms.import_from:
Expand Down Expand Up @@ -87,16 +97,16 @@ def remove_comma():
body.append(trailing_comma)


class SingleRefactorer(RefactoringTool):
def __init__(self, fixer):
self._fixers = [fixer]
class RefactorTool(RefactoringTool):
def __init__(self):
self._fixer = RefactorImports()
self._fixers = [self._fixer]
super().__init__(None)

def get_fixers(self):
return self._fixers, []


def refactor(source, unused_imports):
fixer = RefactorImports(unused_imports)
refactorer = SingleRefactorer(fixer)
return str(refactorer.refactor_string(source, "unimport"))
def refactor_string(self, source, unused_imports):
with self._fixer.clean(unused_imports):
source = super().refactor_string(source, "unimport")
return str(source)
27 changes: 21 additions & 6 deletions unimport/dedect.py → unimport/scan.py
Expand Up @@ -11,18 +11,33 @@ def wrapper(self, node):
return wrapper


class DetectUnusedImport(ast.NodeVisitor):
class Scanner(ast.NodeVisitor):
"To detect unused import using ast"
ignore = ["*", "__future__"]

def __init__(self, source):
def __init__(self, source=None):
self.names = list()
self.imports = list()
self.import_names = set()
try:
self.visit(ast.parse(source=source))
except Exception as e:
print(e)
if source:
self.visit(ast.parse(source))

def iter_imports(self, source):
self.visit(ast.parse(source))
for imp in self.imports:
len_dot = len(imp["name"].split("."))
for name in self.names:
if ".".join(name.split(".")[:len_dot]) == imp["name"]:
break
else:
yield imp

self.clear()

def clear(self):
self.names.clear()
self.imports.clear()
self.import_names.clear()

@recursive
def visit_Import(self, node):
Expand Down

0 comments on commit f3efe47

Please sign in to comment.