blob: 4dd62717cda32a429ffb7c5ffa9eec157c25cb55 [file] [log] [blame]
#!/usr/bin/env python
"""Test suite for autoflake."""
import contextlib
import functools
import io
import os
import re
import shutil
import subprocess
import sys
import tempfile
import unittest
import autoflake
ROOT_DIRECTORY = os.path.abspath(os.path.dirname(__file__))
AUTOFLAKE_COMMAND = [
sys.executable,
os.path.join(
ROOT_DIRECTORY,
"autoflake.py",
),
]
class UnitTests(unittest.TestCase):
"""Unit tests."""
def test_imports(self):
self.assertGreater(len(autoflake.SAFE_IMPORTS), 0)
def test_unused_import_line_numbers(self):
self.assertEqual(
[1],
list(
autoflake.unused_import_line_numbers(
autoflake.check("import os\n"),
),
),
)
def test_unused_import_line_numbers_with_from(self):
self.assertEqual(
[1],
list(
autoflake.unused_import_line_numbers(
autoflake.check("from os import path\n"),
),
),
)
def test_unused_import_line_numbers_with_dot(self):
self.assertEqual(
[1],
list(
autoflake.unused_import_line_numbers(
autoflake.check("import os.path\n"),
),
),
)
def test_extract_package_name(self):
self.assertEqual("os", autoflake.extract_package_name("import os"))
self.assertEqual(
"os",
autoflake.extract_package_name("from os import path"),
)
self.assertEqual(
"os",
autoflake.extract_package_name("import os.path"),
)
def test_extract_package_name_should_ignore_doctest_for_now(self):
self.assertFalse(autoflake.extract_package_name(">>> import os"))
def test_standard_package_names(self):
self.assertIn("os", list(autoflake.standard_package_names()))
self.assertIn("subprocess", list(autoflake.standard_package_names()))
self.assertIn("urllib", list(autoflake.standard_package_names()))
self.assertNotIn("autoflake", list(autoflake.standard_package_names()))
self.assertNotIn("pep8", list(autoflake.standard_package_names()))
def test_get_line_ending(self):
self.assertEqual("\n", autoflake.get_line_ending("\n"))
self.assertEqual("\n", autoflake.get_line_ending("abc\n"))
self.assertEqual("\t \t\n", autoflake.get_line_ending("abc\t \t\n"))
self.assertEqual("", autoflake.get_line_ending("abc"))
self.assertEqual("", autoflake.get_line_ending(""))
def test_get_indentation(self):
self.assertEqual("", autoflake.get_indentation(""))
self.assertEqual(" ", autoflake.get_indentation(" abc"))
self.assertEqual(" ", autoflake.get_indentation(" abc \n\t"))
self.assertEqual("\t", autoflake.get_indentation("\tabc \n\t"))
self.assertEqual(" \t ", autoflake.get_indentation(" \t abc \n\t"))
self.assertEqual("", autoflake.get_indentation(" "))
def test_filter_star_import(self):
self.assertEqual(
"from math import cos",
autoflake.filter_star_import(
"from math import *",
["cos"],
),
)
self.assertEqual(
"from math import cos, sin",
autoflake.filter_star_import(
"from math import *",
["sin", "cos"],
),
)
def test_filter_unused_variable(self):
self.assertEqual(
"foo()",
autoflake.filter_unused_variable("x = foo()"),
)
self.assertEqual(
" foo()",
autoflake.filter_unused_variable(" x = foo()"),
)
def test_filter_unused_variable_with_literal_or_name(self):
self.assertEqual(
"pass",
autoflake.filter_unused_variable("x = 1"),
)
self.assertEqual(
"pass",
autoflake.filter_unused_variable("x = y"),
)
self.assertEqual(
"pass",
autoflake.filter_unused_variable("x = {}"),
)
def test_filter_unused_variable_with_basic_data_structures(self):
self.assertEqual(
"pass",
autoflake.filter_unused_variable("x = dict()"),
)
self.assertEqual(
"pass",
autoflake.filter_unused_variable("x = list()"),
)
self.assertEqual(
"pass",
autoflake.filter_unused_variable("x = set()"),
)
def test_filter_unused_variable_should_ignore_multiline(self):
self.assertEqual(
"x = foo()\\",
autoflake.filter_unused_variable("x = foo()\\"),
)
def test_filter_unused_variable_should_multiple_assignments(self):
self.assertEqual(
"x = y = foo()",
autoflake.filter_unused_variable("x = y = foo()"),
)
def test_filter_unused_variable_with_exception(self):
self.assertEqual(
"except Exception:",
autoflake.filter_unused_variable("except Exception as exception:"),
)
self.assertEqual(
"except (ImportError, ValueError):",
autoflake.filter_unused_variable(
"except (ImportError, ValueError) as foo:",
),
)
def test_filter_unused_variable_drop_rhs(self):
self.assertEqual(
"",
autoflake.filter_unused_variable(
"x = foo()",
drop_rhs=True,
),
)
self.assertEqual(
"",
autoflake.filter_unused_variable(
" x = foo()",
drop_rhs=True,
),
)
def test_filter_unused_variable_with_literal_or_name_drop_rhs(self):
self.assertEqual(
"pass",
autoflake.filter_unused_variable("x = 1", drop_rhs=True),
)
self.assertEqual(
"pass",
autoflake.filter_unused_variable("x = y", drop_rhs=True),
)
self.assertEqual(
"pass",
autoflake.filter_unused_variable("x = {}", drop_rhs=True),
)
def test_filter_unused_variable_with_basic_data_structures_drop_rhs(self):
self.assertEqual(
"pass",
autoflake.filter_unused_variable("x = dict()", drop_rhs=True),
)
self.assertEqual(
"pass",
autoflake.filter_unused_variable("x = list()", drop_rhs=True),
)
self.assertEqual(
"pass",
autoflake.filter_unused_variable("x = set()", drop_rhs=True),
)
def test_filter_unused_variable_should_ignore_multiline_drop_rhs(self):
self.assertEqual(
"x = foo()\\",
autoflake.filter_unused_variable("x = foo()\\", drop_rhs=True),
)
def test_filter_unused_variable_should_multiple_assignments_drop_rhs(self):
self.assertEqual(
"x = y = foo()",
autoflake.filter_unused_variable("x = y = foo()", drop_rhs=True),
)
def test_filter_unused_variable_with_exception_drop_rhs(self):
self.assertEqual(
"except Exception:",
autoflake.filter_unused_variable(
"except Exception as exception:",
drop_rhs=True,
),
)
self.assertEqual(
"except (ImportError, ValueError):",
autoflake.filter_unused_variable(
"except (ImportError, ValueError) as foo:",
drop_rhs=True,
),
)
def test_filter_code(self):
self.assertEqual(
"""\
import os
pass
os.foo()
""",
"".join(
autoflake.filter_code(
"""\
import os
import re
os.foo()
""",
),
),
)
def test_filter_code_with_indented_import(self):
self.assertEqual(
"""\
import os
if True:
pass
os.foo()
""",
"".join(
autoflake.filter_code(
"""\
import os
if True:
import re
os.foo()
""",
),
),
)
def test_filter_code_with_from(self):
self.assertEqual(
"""\
pass
x = 1
""",
"".join(
autoflake.filter_code(
"""\
from os import path
x = 1
""",
),
),
)
def test_filter_code_with_not_from(self):
self.assertEqual(
"""\
pass
x = 1
""",
"".join(
autoflake.filter_code(
"""\
import frommer
x = 1
""",
remove_all_unused_imports=True,
),
),
)
def test_filter_code_with_used_from(self):
self.assertEqual(
"""\
import frommer
print(frommer)
""",
"".join(
autoflake.filter_code(
"""\
import frommer
print(frommer)
""",
remove_all_unused_imports=True,
),
),
)
def test_filter_code_with_ambiguous_from(self):
self.assertEqual(
"""\
pass
""",
"".join(
autoflake.filter_code(
"""\
from frommer import abc, frommer, xyz
""",
remove_all_unused_imports=True,
),
),
)
def test_filter_code_should_avoid_inline_except(self):
line = """\
try: from zap import foo
except: from zap import bar
"""
self.assertEqual(
line,
"".join(
autoflake.filter_code(
line,
remove_all_unused_imports=True,
),
),
)
def test_filter_code_should_avoid_escaped_newlines(self):
line = """\
try:\\
from zap import foo
except:\\
from zap import bar
"""
self.assertEqual(
line,
"".join(
autoflake.filter_code(
line,
remove_all_unused_imports=True,
),
),
)
def test_filter_code_with_remove_all_unused_imports(self):
self.assertEqual(
"""\
pass
pass
x = 1
""",
"".join(
autoflake.filter_code(
"""\
import foo
import zap
x = 1
""",
remove_all_unused_imports=True,
),
),
)
def test_filter_code_with_additional_imports(self):
self.assertEqual(
"""\
pass
import zap
x = 1
""",
"".join(
autoflake.filter_code(
"""\
import foo
import zap
x = 1
""",
additional_imports=["foo", "bar"],
),
),
)
def test_filter_code_should_ignore_imports_with_inline_comment(self):
self.assertEqual(
"""\
from os import path # foo
pass
from fake_foo import z # foo, foo, zap
x = 1
""",
"".join(
autoflake.filter_code(
"""\
from os import path # foo
from os import path
from fake_foo import z # foo, foo, zap
x = 1
""",
),
),
)
def test_filter_code_should_respect_noqa(self):
self.assertEqual(
"""\
pass
import re # noqa
from subprocess import Popen # NOQA
x = 1
""",
"".join(
autoflake.filter_code(
"""\
from os import path
import re # noqa
from subprocess import Popen # NOQA
x = 1
""",
),
),
)
def test_filter_code_expand_star_imports(self):
self.assertEqual(
"""\
from math import sin
sin(1)
""",
"".join(
autoflake.filter_code(
"""\
from math import *
sin(1)
""",
expand_star_imports=True,
),
),
)
self.assertEqual(
"""\
from math import cos, sin
sin(1)
cos(1)
""",
"".join(
autoflake.filter_code(
"""\
from math import *
sin(1)
cos(1)
""",
expand_star_imports=True,
),
),
)
def test_filter_code_ignore_multiple_star_import(self):
self.assertEqual(
"""\
from math import *
from re import *
sin(1)
cos(1)
""",
"".join(
autoflake.filter_code(
"""\
from math import *
from re import *
sin(1)
cos(1)
""",
expand_star_imports=True,
),
),
)
def test_filter_code_with_special_re_symbols_in_key(self):
self.assertEqual(
"""\
a = {
'????': 2,
}
print(a)
""",
"".join(
autoflake.filter_code(
"""\
a = {
'????': 3,
'????': 2,
}
print(a)
""",
remove_duplicate_keys=True,
),
),
)
def test_multiline_import(self):
self.assertTrue(
autoflake.multiline_import(
r"""\
import os, \
math, subprocess
""",
),
)
self.assertFalse(
autoflake.multiline_import(
"""\
import os, math, subprocess
""",
),
)
self.assertTrue(
autoflake.multiline_import(
"""\
import os, math, subprocess
""",
previous_line="if: \\\n",
),
)
self.assertTrue(
autoflake.multiline_import("from os import (path, sep)"),
)
def test_multiline_statement(self):
self.assertFalse(autoflake.multiline_statement("x = foo()"))
self.assertTrue(autoflake.multiline_statement("x = 1;"))
self.assertTrue(autoflake.multiline_statement("import os, \\"))
self.assertTrue(autoflake.multiline_statement("foo("))
self.assertTrue(
autoflake.multiline_statement(
"1",
previous_line="x = \\",
),
)
def test_break_up_import(self):
self.assertEqual(
"import abc\nimport subprocess\nimport math\n",
autoflake.break_up_import("import abc, subprocess, math\n"),
)
def test_break_up_import_with_indentation(self):
self.assertEqual(
" import abc\n import subprocess\n import math\n",
autoflake.break_up_import(" import abc, subprocess, math\n"),
)
def test_break_up_import_should_do_nothing_on_no_line_ending(self):
self.assertEqual(
"import abc, subprocess, math",
autoflake.break_up_import("import abc, subprocess, math"),
)
def test_filter_from_import_no_remove(self):
self.assertEqual(
"""\
from foo import abc, subprocess, math\n""",
autoflake.filter_from_import(
" from foo import abc, subprocess, math\n",
unused_module=[],
),
)
def test_filter_from_import_remove_module(self):
self.assertEqual(
"""\
from foo import subprocess, math\n""",
autoflake.filter_from_import(
" from foo import abc, subprocess, math\n",
unused_module=["foo.abc"],
),
)
def test_filter_from_import_remove_all(self):
self.assertEqual(
" pass\n",
autoflake.filter_from_import(
" from foo import abc, subprocess, math\n",
unused_module=[
"foo.abc",
"foo.subprocess",
"foo.math",
],
),
)
def test_filter_code_multiline_imports(self):
self.assertEqual(
r"""\
import os
pass
import os
os.foo()
""",
"".join(
autoflake.filter_code(
r"""\
import os
import re
import os, \
math, subprocess
os.foo()
""",
),
),
)
def test_filter_code_multiline_from_imports(self):
self.assertEqual(
r"""\
import os
pass
from os.path import (
join,
)
join('a', 'b')
pass
os.foo()
from os.path import \
isdir
isdir('42')
""",
"".join(
autoflake.filter_code(
r"""\
import os
import re
from os.path import (
exists,
join,
)
join('a', 'b')
from os.path import \
abspath, basename, \
commonpath
os.foo()
from os.path import \
isfile \
, isdir
isdir('42')
""",
),
),
)
def test_filter_code_should_ignore_semicolons(self):
self.assertEqual(
r"""\
import os
pass
import os; import math, subprocess
os.foo()
""",
"".join(
autoflake.filter_code(
r"""\
import os
import re
import os; import math, subprocess
os.foo()
""",
),
),
)
def test_filter_code_should_ignore_non_standard_library(self):
self.assertEqual(
"""\
import os
import my_own_module
pass
from my_package import another_module
from my_package import subprocess
from my_blah.my_blah_blah import blah
os.foo()
""",
"".join(
autoflake.filter_code(
"""\
import os
import my_own_module
import re
from my_package import another_module
from my_package import subprocess
from my_blah.my_blah_blah import blah
os.foo()
""",
),
),
)
def test_filter_code_should_ignore_unsafe_imports(self):
self.assertEqual(
"""\
import rlcompleter
pass
pass
pass
print(1)
""",
"".join(
autoflake.filter_code(
"""\
import rlcompleter
import sys
import io
import os
print(1)
""",
),
),
)
def test_filter_code_should_ignore_docstring(self):
line = """
def foo():
'''
>>> import math
'''
"""
self.assertEqual(line, "".join(autoflake.filter_code(line)))
def test_with_ignore_init_module_imports_flag(self):
# Need a temp directory in order to specify file name as __init__.py
temp_directory = tempfile.mkdtemp(dir=".")
temp_file = os.path.join(temp_directory, "__init__.py")
try:
with open(temp_file, "w") as output:
output.write("import re\n")
p = subprocess.Popen(
list(AUTOFLAKE_COMMAND) + ["--ignore-init-module-imports", temp_file],
stdout=subprocess.PIPE,
)
result = p.communicate()[0].decode("utf-8")
self.assertNotIn("import re", result)
finally:
shutil.rmtree(temp_directory)
def test_without_ignore_init_module_imports_flag(self):
# Need a temp directory in order to specify file name as __init__.py
temp_directory = tempfile.mkdtemp(dir=".")
temp_file = os.path.join(temp_directory, "__init__.py")
try:
with open(temp_file, "w") as output:
output.write("import re\n")
p = subprocess.Popen(
list(AUTOFLAKE_COMMAND) + [temp_file],
stdout=subprocess.PIPE,
)
result = p.communicate()[0].decode("utf-8")
self.assertIn("import re", result)
finally:
shutil.rmtree(temp_directory)
def test_fix_code(self):
self.assertEqual(
"""\
import os
import math
from sys import version
os.foo()
math.pi
x = version
""",
autoflake.fix_code(
"""\
import os
import re
import abc, math, subprocess
from sys import exit, version
os.foo()
math.pi
x = version
""",
),
)
def test_fix_code_with_from_and_as(self):
self.assertEqual(
"""\
from collections import namedtuple as xyz
xyz
""",
autoflake.fix_code(
"""\
from collections import defaultdict, namedtuple as xyz
xyz
""",
),
)
self.assertEqual(
"""\
from collections import namedtuple as xyz
xyz
""",
autoflake.fix_code(
"""\
from collections import defaultdict as abc, namedtuple as xyz
xyz
""",
),
)
self.assertEqual(
"""\
from collections import namedtuple
namedtuple
""",
autoflake.fix_code(
"""\
from collections import defaultdict as abc, namedtuple
namedtuple
""",
),
)
self.assertEqual(
"""\
""",
autoflake.fix_code(
"""\
from collections import defaultdict as abc, namedtuple as xyz
""",
),
)
def test_fix_code_with_from_with_and_without_remove_all(self):
code = """\
from x import a as b, c as d
"""
self.assertEqual(
"""\
""",
autoflake.fix_code(code, remove_all_unused_imports=True),
)
self.assertEqual(
code,
autoflake.fix_code(code, remove_all_unused_imports=False),
)
def test_fix_code_with_from_and_depth_module(self):
self.assertEqual(
"""\
from distutils.version import StrictVersion
StrictVersion('1.0.0')
""",
autoflake.fix_code(
"""\
from distutils.version import LooseVersion, StrictVersion
StrictVersion('1.0.0')
""",
),
)
self.assertEqual(
"""\
from distutils.version import StrictVersion as version
version('1.0.0')
""",
autoflake.fix_code(
"""\
from distutils.version import LooseVersion, StrictVersion as version
version('1.0.0')
""",
),
)
def test_fix_code_with_indented_from(self):
self.assertEqual(
"""\
def z():
from ctypes import POINTER, byref
POINTER, byref
""",
autoflake.fix_code(
"""\
def z():
from ctypes import c_short, c_uint, c_int, c_long, pointer, POINTER, byref
POINTER, byref
""",
),
)
self.assertEqual(
"""\
def z():
pass
""",
autoflake.fix_code(
"""\
def z():
from ctypes import c_short, c_uint, c_int, c_long, pointer, POINTER, byref
""",
),
)
def test_fix_code_with_empty_string(self):
self.assertEqual(
"",
autoflake.fix_code(""),
)
def test_fix_code_with_from_and_as_and_escaped_newline(self):
"""Make sure stuff after escaped newline is not lost."""
result = autoflake.fix_code(
"""\
from collections import defaultdict, namedtuple \\
as xyz
xyz
""",
)
# We currently leave lines with escaped newlines as is. But in the
# future this we may parse them and remove unused import accordingly.
# For now, we'll work around it here.
result = re.sub(r" *\\\n *as ", " as ", result)
self.assertEqual(
"""\
from collections import namedtuple as xyz
xyz
""",
autoflake.fix_code(result),
)
def test_fix_code_with_unused_variables(self):
self.assertEqual(
"""\
def main():
y = 11
print(y)
""",
autoflake.fix_code(
"""\
def main():
x = 10
y = 11
print(y)
""",
remove_unused_variables=True,
),
)
def test_fix_code_with_unused_variables_drop_rhs(self):
self.assertEqual(
"""\
def main():
y = 11
print(y)
""",
autoflake.fix_code(
"""\
def main():
x = 10
y = 11
print(y)
""",
remove_unused_variables=True,
remove_rhs_for_unused_variables=True,
),
)
def test_fix_code_with_unused_variables_should_skip_nonlocal(self):
"""pyflakes does not handle nonlocal correctly."""
code = """\
def bar():
x = 1
def foo():
nonlocal x
x = 2
"""
self.assertEqual(
code,
autoflake.fix_code(
code,
remove_unused_variables=True,
),
)
def test_fix_code_with_unused_variables_should_skip_nonlocal_drop_rhs(
self,
):
"""pyflakes does not handle nonlocal correctly."""
code = """\
def bar():
x = 1
def foo():
nonlocal x
x = 2
"""
self.assertEqual(
code,
autoflake.fix_code(
code,
remove_unused_variables=True,
remove_rhs_for_unused_variables=True,
),
)
def test_detect_encoding_with_bad_encoding(self):
with temporary_file("# -*- coding: blah -*-\n") as filename:
self.assertEqual(
"latin-1",
autoflake.detect_encoding(filename),
)
def test_fix_code_with_comma_on_right(self):
"""pyflakes does not handle nonlocal correctly."""
self.assertEqual(
"""\
def main():
pass
""",
autoflake.fix_code(
"""\
def main():
x = (1, 2, 3)
""",
remove_unused_variables=True,
),
)
def test_fix_code_with_comma_on_right_drop_rhs(self):
"""pyflakes does not handle nonlocal correctly."""
self.assertEqual(
"""\
def main():
pass
""",
autoflake.fix_code(
"""\
def main():
x = (1, 2, 3)
""",
remove_unused_variables=True,
remove_rhs_for_unused_variables=True,
),
)
def test_fix_code_with_unused_variables_should_skip_multiple(self):
code = """\
def main():
(x, y, z) = (1, 2, 3)
print(z)
"""
self.assertEqual(
code,
autoflake.fix_code(
code,
remove_unused_variables=True,
),
)
def test_fix_code_with_unused_variables_should_skip_multiple_drop_rhs(
self,
):
code = """\
def main():
(x, y, z) = (1, 2, 3)
print(z)
"""
self.assertEqual(
code,
autoflake.fix_code(
code,
remove_unused_variables=True,
remove_rhs_for_unused_variables=True,
),
)
def test_fix_code_should_handle_pyflakes_recursion_error_gracefully(self):
code = "x = [{}]".format("+".join(["abc" for _ in range(2000)]))
self.assertEqual(
code,
autoflake.fix_code(code),
)
def test_fix_code_with_duplicate_key(self):
self.assertEqual(
"""\
a = {
(0,1): 3,
}
print(a)
""",
"".join(
autoflake.fix_code(
"""\
a = {
(0,1): 1,
(0, 1): 'two',
(0,1): 3,
}
print(a)
""",
remove_duplicate_keys=True,
),
),
)
def test_fix_code_with_duplicate_key_longer(self):
self.assertEqual(
"""\
{
'a': 0,
'c': 2,
'd': 3,
'e': 4,
'f': 5,
'b': 6,
}
""",
"".join(
autoflake.fix_code(
"""\
{
'a': 0,
'b': 1,
'c': 2,
'd': 3,
'e': 4,
'f': 5,
'b': 6,
}
""",
remove_duplicate_keys=True,
),
),
)
def test_fix_code_with_duplicate_key_with_many_braces(self):
self.assertEqual(
"""\
a = None
{None: {None: None},
}
{
None: a.b,
}
""",
"".join(
autoflake.fix_code(
"""\
a = None
{None: {None: None},
}
{
None: a.a,
None: a.b,
}
""",
remove_duplicate_keys=True,
),
),
)
def test_fix_code_should_ignore_complex_case_of_duplicate_key(self):
"""We only handle simple cases."""
code = """\
a = {(0,1): 1, (0, 1): 'two',
(0,1): 3,
}
print(a)
"""
self.assertEqual(
code,
"".join(
autoflake.fix_code(
code,
remove_duplicate_keys=True,
),
),
)
def test_fix_code_should_ignore_complex_case_of_duplicate_key_comma(self):
"""We only handle simple cases."""
code = """\
{
1: {0,
},
1: {2,
},
}
"""
self.assertEqual(
code,
"".join(
autoflake.fix_code(
code,
remove_duplicate_keys=True,
),
),
)
def test_fix_code_should_ignore_complex_case_of_duplicate_key_partially(
self,
):
"""We only handle simple cases."""
code = """\
a = {(0,1): 1, (0, 1): 'two',
(0,1): 3,
(2,3): 4,
(2,3): 4,
(2,3): 5,
}
print(a)
"""
self.assertEqual(
"""\
a = {(0,1): 1, (0, 1): 'two',
(0,1): 3,
(2,3): 5,
}
print(a)
""",
"".join(
autoflake.fix_code(
code,
remove_duplicate_keys=True,
),
),
)
def test_fix_code_should_ignore_more_cases_of_duplicate_key(self):
"""We only handle simple cases."""
code = """\
a = {
(0,1):
1,
(0, 1): 'two',
(0,1): 3,
}
print(a)
"""
self.assertEqual(
code,
"".join(
autoflake.fix_code(
code,
remove_duplicate_keys=True,
),
),
)
def test_fix_code_should_ignore_duplicate_key_with_comments(self):
"""We only handle simple cases."""
code = """\
a = {
(0,1) # : f
:
1,
(0, 1): 'two',
(0,1): 3,
}
print(a)
"""
self.assertEqual(
code,
"".join(
autoflake.fix_code(
code,
remove_duplicate_keys=True,
),
),
)
code = """\
{
1: {0,
},
1: #{2,
#},
0
}
"""
self.assertEqual(
code,
"".join(
autoflake.fix_code(
code,
remove_duplicate_keys=True,
),
),
)
def test_fix_code_should_ignore_duplicate_key_with_multiline_key(self):
"""We only handle simple cases."""
code = """\
a = {
(0,1
): 1,
(0, 1): 'two',
(0,1): 3,
}
print(a)
"""
self.assertEqual(
code,
"".join(
autoflake.fix_code(
code,
remove_duplicate_keys=True,
),
),
)
def test_fix_code_should_ignore_duplicate_key_with_no_comma(self):
"""We don't want to delete the line and leave a lone comma."""
code = """\
a = {
(0,1) : 1
,
(0, 1): 'two',
(0,1): 3,
}
print(a)
"""
self.assertEqual(
code,
"".join(
autoflake.fix_code(
code,
remove_duplicate_keys=True,
),
),
)
def test_fix_code_keeps_pass_statements(self):
code = """\
if True:
pass
else:
def foo():
\"\"\" A docstring. \"\"\"
pass
def foo2():
\"\"\" A docstring. \"\"\"
pass
def foo3():
\"\"\" A docstring. \"\"\"
pass
def bar():
# abc
pass
def blah():
123
pass
pass # Nope.
pass
"""
self.assertEqual(
code,
"".join(
autoflake.fix_code(
code,
ignore_pass_statements=True,
),
),
)
def test_fix_code_keeps_passes_after_docstrings(self):
actual = autoflake.fix_code(
"""\
if True:
pass
else:
def foo():
\"\"\" A docstring. \"\"\"
pass
def foo2():
\"\"\" A docstring. \"\"\"
pass
def foo3():
\"\"\" A docstring. \"\"\"
pass
def bar():
# abc
pass
def blah():
123
pass
pass # Nope.
pass
""",
ignore_pass_after_docstring=True,
)
expected = """\
if True:
pass
else:
def foo():
\"\"\" A docstring. \"\"\"
pass
def foo2():
\"\"\" A docstring. \"\"\"
pass
def foo3():
\"\"\" A docstring. \"\"\"
pass
def bar():
# abc
pass
def blah():
123
pass # Nope.
"""
self.assertEqual(actual, expected)
def test_useless_pass_line_numbers(self):
self.assertEqual(
[1],
list(
autoflake.useless_pass_line_numbers(
"pass\n",
),
),
)
self.assertEqual(
[],
list(
autoflake.useless_pass_line_numbers(
"if True:\n pass\n",
),
),
)
def test_useless_pass_line_numbers_with_escaped_newline(self):
self.assertEqual(
[],
list(
autoflake.useless_pass_line_numbers(
"if True:\\\n pass\n",
),
),
)
def test_useless_pass_line_numbers_with_more_complex(self):
self.assertEqual(
[6],
list(
autoflake.useless_pass_line_numbers(
"""\
if True:
pass
else:
True
x = 1
pass
""",
),
),
)
def test_useless_pass_line_numbers_after_docstring(self):
actual_pass_line_numbers = list(
autoflake.useless_pass_line_numbers(
"""\
@abc.abstractmethod
def some_abstract_method():
\"\"\"Some docstring.\"\"\"
pass
""",
),
)
expected_pass_line_numbers = [4]
self.assertEqual(expected_pass_line_numbers, actual_pass_line_numbers)
def test_useless_pass_line_numbers_keep_pass_after_docstring(self):
actual_pass_line_numbers = list(
autoflake.useless_pass_line_numbers(
"""\
@abc.abstractmethod
def some_abstract_method():
\"\"\"Some docstring.\"\"\"
pass
""",
ignore_pass_after_docstring=True,
),
)
expected_pass_line_numbers = []
self.assertEqual(expected_pass_line_numbers, actual_pass_line_numbers)
def test_filter_useless_pass(self):
self.assertEqual(
"""\
if True:
pass
else:
True
x = 1
""",
"".join(
autoflake.filter_useless_pass(
"""\
if True:
pass
else:
True
x = 1
pass
""",
),
),
)
def test_filter_useless_pass_with_syntax_error(self):
source = """\
if True:
if True:
if True:
if True:
if True:
pass
else:
True
pass
pass
x = 1
"""
self.assertEqual(
source,
"".join(autoflake.filter_useless_pass(source)),
)
def test_filter_useless_pass_more_complex(self):
self.assertEqual(
"""\
if True:
pass
else:
def foo():
pass
# abc
def bar():
# abc
pass
def blah():
123
pass # Nope.
True
x = 1
""",
"".join(
autoflake.filter_useless_pass(
"""\
if True:
pass
else:
def foo():
pass
# abc
def bar():
# abc
pass
def blah():
123
pass
pass # Nope.
pass
True
x = 1
pass
""",
),
),
)
def test_filter_useless_pass_keep_pass_after_docstring(self):
source = """\
def foo():
\"\"\" This is not a useless 'pass'. \"\"\"
pass
@abc.abstractmethod
def bar():
\"\"\"
Also this is not a useless 'pass'.
\"\"\"
pass
"""
self.assertEqual(
source,
"".join(
autoflake.filter_useless_pass(
source,
ignore_pass_after_docstring=True,
),
),
)
def test_filter_useless_pass_keeps_pass_statements(self):
source = """\
if True:
pass
pass
pass
pass
else:
pass
True
x = 1
pass
"""
self.assertEqual(
source,
"".join(
autoflake.filter_useless_pass(
source,
ignore_pass_statements=True,
),
),
)
def test_filter_useless_paspasss_with_try(self):
self.assertEqual(
"""\
import os
os.foo()
try:
pass
except ImportError:
pass
""",
"".join(
autoflake.filter_useless_pass(
"""\
import os
os.foo()
try:
pass
pass
except ImportError:
pass
""",
),
),
)
def test_filter_useless_pass_leading_pass(self):
self.assertEqual(
"""\
if True:
pass
else:
True
x = 1
""",
"".join(
autoflake.filter_useless_pass(
"""\
if True:
pass
pass
pass
pass
else:
pass
True
x = 1
pass
""",
),
),
)
def test_filter_useless_pass_leading_pass_with_number(self):
self.assertEqual(
"""\
def func11():
0, 11 / 2
return 1
""",
"".join(
autoflake.filter_useless_pass(
"""\
def func11():
pass
0, 11 / 2
return 1
""",
),
),
)
def test_filter_useless_pass_leading_pass_with_string(self):
self.assertEqual(
"""\
def func11():
'hello'
return 1
""",
"".join(
autoflake.filter_useless_pass(
"""\
def func11():
pass
'hello'
return 1
""",
),
),
)
def test_check(self):
self.assertTrue(autoflake.check("import os"))
def test_check_with_bad_syntax(self):
self.assertFalse(autoflake.check("foo("))
def test_check_with_unicode(self):
self.assertFalse(autoflake.check('print("∑")'))
self.assertTrue(autoflake.check("import os # ∑"))
def test_get_diff_text(self):
# We ignore the first two lines since it differs on Python 2.6.
self.assertEqual(
"""\
-foo
+bar
""",
"\n".join(
autoflake.get_diff_text(["foo\n"], ["bar\n"], "").split(
"\n",
)[3:],
),
)
def test_get_diff_text_without_newline(self):
# We ignore the first two lines since it differs on Python 2.6.
self.assertEqual(
"""\
-foo
\\ No newline at end of file
+foo
""",
"\n".join(
autoflake.get_diff_text(["foo"], ["foo\n"], "").split(
"\n",
)[3:],
),
)
def test_is_literal_or_name(self):
self.assertTrue(autoflake.is_literal_or_name("123"))
self.assertTrue(autoflake.is_literal_or_name("[1, 2, 3]"))
self.assertTrue(autoflake.is_literal_or_name("xyz"))
self.assertFalse(autoflake.is_literal_or_name("xyz.prop"))
self.assertFalse(autoflake.is_literal_or_name(" "))
def test_is_python_file(self):
self.assertTrue(
autoflake.is_python_file(
os.path.join(ROOT_DIRECTORY, "autoflake.py"),
),
)
with temporary_file("#!/usr/bin/env python", suffix="") as filename:
self.assertTrue(autoflake.is_python_file(filename))
with temporary_file("#!/usr/bin/python", suffix="") as filename:
self.assertTrue(autoflake.is_python_file(filename))
with temporary_file("#!/usr/bin/python3", suffix="") as filename:
self.assertTrue(autoflake.is_python_file(filename))
with temporary_file("#!/usr/bin/pythonic", suffix="") as filename:
self.assertFalse(autoflake.is_python_file(filename))
with temporary_file("###!/usr/bin/python", suffix="") as filename:
self.assertFalse(autoflake.is_python_file(filename))
self.assertFalse(autoflake.is_python_file(os.devnull))
self.assertFalse(autoflake.is_python_file("/bin/bash"))
def test_is_exclude_file(self):
self.assertTrue(
autoflake.is_exclude_file(
"1.py",
["test*", "1*"],
),
)
self.assertFalse(
autoflake.is_exclude_file(
"2.py",
["test*", "1*"],
),
)
# folder glob
self.assertTrue(
autoflake.is_exclude_file(
"test/test.py",
["test/**.py"],
),
)
self.assertTrue(
autoflake.is_exclude_file(
"test/auto_test.py",
["test/*_test.py"],
),
)
self.assertFalse(
autoflake.is_exclude_file(
"test/auto_auto.py",
["test/*_test.py"],
),
)
def test_match_file(self):
with temporary_file("", suffix=".py", prefix=".") as filename:
self.assertFalse(
autoflake.match_file(filename, exclude=[]),
msg=filename,
)
self.assertFalse(autoflake.match_file(os.devnull, exclude=[]))
with temporary_file("", suffix=".py", prefix="") as filename:
self.assertTrue(
autoflake.match_file(filename, exclude=[]),
msg=filename,
)
def test_find_files(self):
temp_directory = tempfile.mkdtemp()
try:
target = os.path.join(temp_directory, "dir")
os.mkdir(target)
with open(os.path.join(target, "a.py"), "w"):
pass
exclude = os.path.join(target, "ex")
os.mkdir(exclude)
with open(os.path.join(exclude, "b.py"), "w"):
pass
sub = os.path.join(exclude, "sub")
os.mkdir(sub)
with open(os.path.join(sub, "c.py"), "w"):
pass
# FIXME: Avoid changing directory. This may interfere with parallel
# test runs.
cwd = os.getcwd()
os.chdir(temp_directory)
try:
files = list(
autoflake.find_files(
["dir"],
True,
[os.path.join("dir", "ex")],
),
)
finally:
os.chdir(cwd)
file_names = [os.path.basename(f) for f in files]
self.assertIn("a.py", file_names)
self.assertNotIn("b.py", file_names)
self.assertNotIn("c.py", file_names)
finally:
shutil.rmtree(temp_directory)
def test_exclude(self):
temp_directory = tempfile.mkdtemp(dir=".")
try:
with open(os.path.join(temp_directory, "a.py"), "w") as output:
output.write("import re\n")
os.mkdir(os.path.join(temp_directory, "d"))
with open(
os.path.join(temp_directory, "d", "b.py"),
"w",
) as output:
output.write("import os\n")
p = subprocess.Popen(
list(AUTOFLAKE_COMMAND)
+ [temp_directory, "--recursive", "--exclude=a*"],
stdout=subprocess.PIPE,
)
result = p.communicate()[0].decode("utf-8")
self.assertNotIn("import re", result)
self.assertIn("import os", result)
finally:
shutil.rmtree(temp_directory)
class SystemTests(unittest.TestCase):
"""System tests."""
def test_diff(self):
with temporary_file(
"""\
import re
import os
import my_own_module
x = 1
""",
) as filename:
output_file = io.StringIO()
autoflake._main(
argv=["my_fake_program", filename],
standard_out=output_file,
standard_error=None,
)
self.assertEqual(
"""\
-import re
-import os
import my_own_module
x = 1
""",
"\n".join(output_file.getvalue().split("\n")[3:]),
)
def test_diff_with_nonexistent_file(self):
output_file = io.StringIO()
autoflake._main(
argv=["my_fake_program", "nonexistent_file"],
standard_out=output_file,
standard_error=output_file,
)
self.assertIn("no such file", output_file.getvalue().lower())
def test_diff_with_encoding_declaration(self):
with temporary_file(
"""\
# coding: iso-8859-1
import re
import os
import my_own_module
x = 1
""",
) as filename:
output_file = io.StringIO()
autoflake._main(
argv=["my_fake_program", filename],
standard_out=output_file,
standard_error=None,
)
self.assertEqual(
"""\
# coding: iso-8859-1
-import re
-import os
import my_own_module
x = 1
""",
"\n".join(output_file.getvalue().split("\n")[3:]),
)
def test_in_place(self):
with temporary_file(
"""\
import foo
x = foo
import subprocess
x()
try:
import os
except ImportError:
import os
""",
) as filename:
output_file = io.StringIO()
autoflake._main(
argv=["my_fake_program", "--in-place", filename],
standard_out=output_file,
standard_error=None,
)
with open(filename) as f:
self.assertEqual(
"""\
import foo
x = foo
x()
try:
pass
except ImportError:
pass
""",
f.read(),
)
def test_check_with_empty_file(self):
line = ""
with temporary_file(line) as filename:
output_file = io.StringIO()
autoflake._main(
argv=["my_fake_program", "--check", filename],
standard_out=output_file,
standard_error=None,
)
self.assertEqual(
f"{filename}: No issues detected!{os.linesep}",
output_file.getvalue(),
)
def test_check_correct_file(self):
with temporary_file(
"""\
import foo
x = foo.bar
print(x)
""",
) as filename:
output_file = io.StringIO()
autoflake._main(
argv=["my_fake_program", "--check", filename],
standard_out=output_file,
standard_error=None,
)
self.assertEqual(
f"{filename}: No issues detected!{os.linesep}",
output_file.getvalue(),
)
def test_check_correct_file_with_quiet(self):
with temporary_file(
"""\
import foo
x = foo.bar
print(x)
""",
) as filename:
output_file = io.StringIO()
autoflake._main(
argv=[
"my_fake_program",
"--check",
"--quiet",
filename,
],
standard_out=output_file,
standard_error=None,
)
self.assertEqual("", output_file.getvalue())
def test_check_useless_pass(self):
with temporary_file(
"""\
import foo
x = foo
import subprocess
x()
try:
pass
import os
except ImportError:
pass
import os
import sys
""",
) as filename:
output_file = io.StringIO()
exit_status = autoflake._main(
argv=["my_fake_program", "--check", filename],
standard_out=output_file,
standard_error=None,
)
self.assertEqual(exit_status, 1)
self.assertEqual(
f"{filename}: Unused imports/variables detected{os.linesep}",
output_file.getvalue(),
)
def test_check_with_multiple_files(self):
with temporary_file("import sys") as file1:
with temporary_file("import sys") as file2:
output_file = io.StringIO()
exit_status = autoflake._main(
argv=["my_fake_program", "--check", file1, file2],
standard_out=output_file,
standard_error=None,
)
self.assertEqual(exit_status, 1)
self.assertEqual(
{
f"{file1}: Unused imports/variables detected",
f"{file2}: Unused imports/variables detected",
},
set(output_file.getvalue().strip().split(os.linesep)),
)
def test_check_diff_with_empty_file(self):
line = ""
with temporary_file(line) as filename:
output_file = io.StringIO()
autoflake._main(
argv=["my_fake_program", "--check-diff", filename],
standard_out=output_file,
standard_error=None,
)
self.assertEqual(
f"{filename}: No issues detected!{os.linesep}",
output_file.getvalue(),
)
def test_check_diff_correct_file(self):
with temporary_file(
"""\
import foo
x = foo.bar
print(x)
""",
) as filename:
output_file = io.StringIO()
autoflake._main(
argv=["my_fake_program", "--check-diff", filename],
standard_out=output_file,
standard_error=None,
)
self.assertEqual(
f"{filename}: No issues detected!{os.linesep}",
output_file.getvalue(),
)
def test_check_diff_correct_file_with_quiet(self):
with temporary_file(
"""\
import foo
x = foo.bar
print(x)
""",
) as filename:
output_file = io.StringIO()
autoflake._main(
argv=[
"my_fake_program",
"--check-diff",
"--quiet",
filename,
],
standard_out=output_file,
standard_error=None,
)
self.assertEqual("", output_file.getvalue())
def test_check_diff_useless_pass(self):
with temporary_file(
"""\
import foo
x = foo
import subprocess
x()
try:
pass
import os
except ImportError:
pass
import os
import sys
""",
) as filename:
output_file = io.StringIO()
exit_status = autoflake._main(
argv=["my_fake_program", "--check-diff", filename],
standard_out=output_file,
standard_error=None,
)
self.assertEqual(exit_status, 1)
self.assertEqual(
"""\
import foo
x = foo
-import subprocess
x()
try:
pass
- import os
except ImportError:
pass
- import os
- import sys
""",
"\n".join(output_file.getvalue().split("\n")[3:]),
)
def test_in_place_with_empty_file(self):
line = ""
with temporary_file(line) as filename:
output_file = io.StringIO()
autoflake._main(
argv=["my_fake_program", "--in-place", filename],
standard_out=output_file,
standard_error=None,
)
with open(filename) as f:
self.assertEqual(line, f.read())
def test_in_place_with_with_useless_pass(self):
with temporary_file(
"""\
import foo
x = foo
import subprocess
x()
try:
pass
import os
except ImportError:
pass
import os
import sys
""",
) as filename:
output_file = io.StringIO()
autoflake._main(
argv=["my_fake_program", "--in-place", filename],
standard_out=output_file,
standard_error=None,
)
with open(filename) as f:
self.assertEqual(
"""\
import foo
x = foo
x()
try:
pass
except ImportError:
pass
""",
f.read(),
)
def test_with_missing_file(self):
output_file = io.StringIO()
ignore = StubFile()
autoflake._main(
argv=["my_fake_program", "--in-place", ".fake"],
standard_out=output_file,
standard_error=ignore,
)
self.assertFalse(output_file.getvalue())
def test_ignore_hidden_directories(self):
with temporary_directory() as directory:
with temporary_directory(
prefix=".",
directory=directory,
) as inner_directory:
with temporary_file(
"""\
import re
import os
""",
directory=inner_directory,
):
output_file = io.StringIO()
autoflake._main(
argv=[
"my_fake_program",
"--recursive",
directory,
],
standard_out=output_file,
standard_error=None,
)
self.assertEqual(
"",
output_file.getvalue().strip(),
)
def test_in_place_and_stdout(self):
output_file = io.StringIO()
self.assertRaises(
SystemExit,
autoflake._main,
argv=["my_fake_program", "--in-place", "--stdout", __file__],
standard_out=output_file,
standard_error=output_file,
)
def test_end_to_end(self):
with temporary_file(
"""\
import fake_fake, fake_foo, fake_bar, fake_zoo
import re, os
x = os.sep
print(x)
""",
) as filename:
process = subprocess.Popen(
AUTOFLAKE_COMMAND
+ [
"--imports=fake_foo,fake_bar",
filename,
],
stdout=subprocess.PIPE,
)
self.assertEqual(
"""\
-import fake_fake, fake_foo, fake_bar, fake_zoo
-import re, os
+import fake_fake
+import fake_zoo
+import os
x = os.sep
print(x)
""",
"\n".join(process.communicate()[0].decode().split(os.linesep)[3:]),
)
def test_end_to_end_multiple_files(self):
with temporary_file(
"""\
import fake_fake, fake_foo, fake_bar, fake_zoo
import re, os
x = os.sep
print(x)
""",
) as filename1:
with temporary_file(
"""\
import os
x = os.sep
print(x)
""",
) as filename2:
process = subprocess.Popen(
AUTOFLAKE_COMMAND
+ [
"--imports=fake_foo,fake_bar",
"--check",
"--jobs=2",
filename1,
filename2,
],
stdout=subprocess.PIPE,
)
status_code = process.wait()
self.assertEqual(1, status_code)
def test_end_to_end_with_remove_all_unused_imports(self):
with temporary_file(
"""\
import fake_fake, fake_foo, fake_bar, fake_zoo
import re, os
x = os.sep
print(x)
""",
) as filename:
process = subprocess.Popen(
AUTOFLAKE_COMMAND
+ [
"--remove-all",
filename,
],
stdout=subprocess.PIPE,
)
self.assertEqual(
"""\
-import fake_fake, fake_foo, fake_bar, fake_zoo
-import re, os
+import os
x = os.sep
print(x)
""",
"\n".join(process.communicate()[0].decode().split(os.linesep)[3:]),
)
def test_end_to_end_with_remove_duplicate_keys_multiple_lines(self):
with temporary_file(
"""\
a = {
'b': 456,
'a': 123,
'b': 7834,
'a': 'wow',
'b': 456,
'c': 'hello',
'c': 'hello2',
'b': 'hiya',
}
print(a)
""",
) as filename:
process = subprocess.Popen(
AUTOFLAKE_COMMAND
+ [
"--remove-duplicate-keys",
filename,
],
stdout=subprocess.PIPE,
)
self.assertEqual(
"""\
a = {
- 'b': 456,
- 'a': 123,
- 'b': 7834,
'a': 'wow',
- 'b': 456,
- 'c': 'hello',
'c': 'hello2',
'b': 'hiya',
}
""",
"\n".join(process.communicate()[0].decode().split(os.linesep)[3:]),
)
def test_end_to_end_with_remove_duplicate_keys_and_other_errors(self):
with temporary_file(
"""\
from math import *
print(sin(4))
a = { # Hello
'b': 456,
'a': 123,
'b': 7834,
'a': 'wow',
'b': 456,
'c': 'hello',
'c': 'hello2',
'b': 'hiya',
}
print(a)
""",
) as filename:
process = subprocess.Popen(
AUTOFLAKE_COMMAND
+ [
"--remove-duplicate-keys",
filename,
],
stdout=subprocess.PIPE,
)
self.assertEqual(
"""\
from math import *
print(sin(4))
a = { # Hello
- 'b': 456,
- 'a': 123,
- 'b': 7834,
'a': 'wow',
- 'b': 456,
- 'c': 'hello',
'c': 'hello2',
'b': 'hiya',
}
""",
"\n".join(process.communicate()[0].decode().split(os.linesep)[3:]),
)
def test_end_to_end_with_remove_duplicate_keys_tuple(self):
with temporary_file(
"""\
a = {
(0,1): 1,
(0, 1): 'two',
(0,1): 3,
}
print(a)
""",
) as filename:
process = subprocess.Popen(
AUTOFLAKE_COMMAND
+ [
"--remove-duplicate-keys",
filename,
],
stdout=subprocess.PIPE,
)
self.assertEqual(
"""\
a = {
- (0,1): 1,
- (0, 1): 'two',
(0,1): 3,
}
print(a)
""",
"\n".join(process.communicate()[0].decode().split(os.linesep)[3:]),
)
def test_end_to_end_with_error(self):
with temporary_file(
"""\
import fake_fake, fake_foo, fake_bar, fake_zoo
import re, os
x = os.sep
print(x)
""",
) as filename:
process = subprocess.Popen(
AUTOFLAKE_COMMAND
+ [
"--imports=fake_foo,fake_bar",
"--remove-all",
filename,
],
stderr=subprocess.PIPE,
)
self.assertIn(
"not allowed with argument",
process.communicate()[1].decode(),
)
def test_end_to_end_from_stdin(self):
stdin_data = b"""\
import fake_fake, fake_foo, fake_bar, fake_zoo
import re, os
x = os.sep
print(x)
"""
process = subprocess.Popen(
AUTOFLAKE_COMMAND + ["--remove-all", "-"],
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
)
stdout, _ = process.communicate(stdin_data)
self.assertEqual(
"""\
import os
x = os.sep
print(x)
""",
"\n".join(stdout.decode().split(os.linesep)),
)
def test_end_to_end_from_stdin_with_in_place(self):
stdin_data = b"""\
import fake_fake, fake_foo, fake_bar, fake_zoo
import re, os, sys
x = os.sep
print(x)
"""
process = subprocess.Popen(
AUTOFLAKE_COMMAND + ["--remove-all", "--in-place", "-"],
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
)
stdout, _ = process.communicate(stdin_data)
self.assertEqual(
"""\
import os
x = os.sep
print(x)
""",
"\n".join(stdout.decode().split(os.linesep)),
)
def test_end_to_end_dont_remove_unused_imports_when_not_using_flag(self):
with temporary_file(
"""\
from . import fake_bar
from . import fake_foo
fake_foo.fake_function()
""",
) as filename:
process = subprocess.Popen(
AUTOFLAKE_COMMAND
+ [
filename,
],
stdout=subprocess.PIPE,
)
self.assertEqual(
"",
"\n".join(process.communicate()[0].decode().split(os.linesep)[3:]),
)
class MultilineFromImportTests(unittest.TestCase):
def test_is_over(self):
filt = autoflake.FilterMultilineImport("from . import (\n")
self.assertTrue(filt.is_over("module)\n"))
self.assertTrue(filt.is_over(" )\n"))
self.assertTrue(filt.is_over(" ) # comment\n"))
self.assertTrue(filt.is_over("from module import (a, b)\n"))
self.assertFalse(filt.is_over("# )"))
self.assertFalse(filt.is_over("module\n"))
self.assertFalse(filt.is_over("module, \\\n"))
self.assertFalse(filt.is_over("\n"))
filt = autoflake.FilterMultilineImport("from . import module, \\\n")
self.assertTrue(filt.is_over("module\n"))
self.assertTrue(filt.is_over("\n"))
self.assertTrue(filt.is_over("m1, m2 # comment with \\\n"))
self.assertFalse(filt.is_over("m1, m2 \\\n"))
self.assertFalse(filt.is_over("m1, m2 \\ #\n"))
self.assertFalse(filt.is_over("m1, m2 \\ # comment with \\\n"))
self.assertFalse(filt.is_over("\\\n"))
# "Multiline" imports that are not really multiline
filt = autoflake.FilterMultilineImport(
"import os; " "import math, subprocess",
)
self.assertTrue(filt.is_over())
unused = ()
def assert_fix(self, lines, result, remove_all=True):
fixer = autoflake.FilterMultilineImport(
lines[0],
remove_all_unused_imports=remove_all,
unused_module=self.unused,
)
fixed = functools.reduce(lambda acc, x: acc(x), lines[1:], fixer())
self.assertEqual(fixed, result)
def test_fix(self):
self.unused = ["third_party.lib" + str(x) for x in (1, 3, 4)]
# Example m0 (isort)
self.assert_fix(
[
"from third_party import (lib1, lib2, lib3,\n",
" lib4, lib5, lib6)\n",
],
"from third_party import (lib2, lib5, lib6)\n",
)
# Example m1(isort)
self.assert_fix(
[
"from third_party import (lib1,\n",
" lib2,\n",
" lib3,\n",
" lib4,\n",
" lib5,\n",
" lib6)\n",
],
"from third_party import (lib2,\n"
" lib5,\n"
" lib6)\n",
)
# Variation m1(isort)
self.assert_fix(
[
"from third_party import (lib1\n",
" ,lib2\n",
" ,lib3\n",
" ,lib4\n",
" ,lib5\n",
" ,lib6)\n",
],
"from third_party import (lib2\n"
" ,lib5\n"
" ,lib6)\n",
)
# Example m2 (isort)
self.assert_fix(
[
"from third_party import \\\n",
" lib1, lib2, lib3, \\\n",
" lib4, lib5, lib6\n",
],
"from third_party import \\\n" " lib2, lib5, lib6\n",
)
# Example m3 (isort)
self.assert_fix(
[
"from third_party import (\n",
" lib1,\n",
" lib2,\n",
" lib3,\n",
" lib4,\n",
" lib5\n",
")\n",
],
"from third_party import (\n" " lib2,\n" " lib5\n" ")\n",
)
# Example m4 (isort)
self.assert_fix(
[
"from third_party import (\n",
" lib1, lib2, lib3, lib4,\n",
" lib5, lib6)\n",
],
"from third_party import (\n" " lib2, lib5, lib6)\n",
)
# Example m5 (isort)
self.assert_fix(
[
"from third_party import (\n",
" lib1, lib2, lib3, lib4,\n",
" lib5, lib6\n",
")\n",
],
"from third_party import (\n" " lib2, lib5, lib6\n" ")\n",
)
# Some Deviations
self.assert_fix(
[
"from third_party import (\n",
" lib1\\\n", # only unused + line continuation
" ,lib2, \n",
" libA\n", # used import with no commas
" ,lib3, \n", # leading and trailing commas + unused import
" libB, \n",
" \\\n", # empty line with continuation
" lib4,\n", # unused import with comment
")\n",
],
"from third_party import (\n"
" lib2\\\n"
" ,libA, \n"
" libB,\n"
")\n",
)
self.assert_fix(
[
"from third_party import (\n",
" lib1\n",
",\n",
" lib2\n",
",\n",
" lib3\n",
",\n",
" lib4\n",
",\n",
" lib5\n",
")\n",
],
"from third_party import (\n" " lib2\n" ",\n" " lib5\n" ")\n",
)
self.assert_fix(
[
"from third_party import (\n",
" lib1 \\\n",
", \\\n",
" lib2 \\\n",
",\\\n",
" lib3\n",
",\n",
" lib4\n",
",\n",
" lib5 \\\n",
")\n",
],
"from third_party import (\n"
" lib2 \\\n"
", \\\n"
" lib5 \\\n"
")\n",
)
def test_indentation(self):
# Some weird indentation examples
self.unused = ["third_party.lib" + str(x) for x in (1, 3, 4)]
self.assert_fix(
[
" from third_party import (\n",
" lib1, lib2, lib3, lib4,\n",
" lib5, lib6\n",
")\n",
],
" from third_party import (\n" " lib2, lib5, lib6\n" ")\n",
)
self.assert_fix(
[
"\tfrom third_party import \\\n",
"\t\tlib1, lib2, lib3, \\\n",
"\t\tlib4, lib5, lib6\n",
],
"\tfrom third_party import \\\n" "\t\tlib2, lib5, lib6\n",
)
def test_fix_relative(self):
# Example m0 (isort)
self.unused = [".lib" + str(x) for x in (1, 3, 4)]
self.assert_fix(
[
"from . import (lib1, lib2, lib3,\n",
" lib4, lib5, lib6)\n",
],
"from . import (lib2, lib5, lib6)\n",
)
# Example m1(isort)
self.unused = ["..lib" + str(x) for x in (1, 3, 4)]
self.assert_fix(
[
"from .. import (lib1,\n",
" lib2,\n",
" lib3,\n",
" lib4,\n",
" lib5,\n",
" lib6)\n",
],
"from .. import (lib2,\n"
" lib5,\n"
" lib6)\n",
)
# Example m2 (isort)
self.unused = ["...lib" + str(x) for x in (1, 3, 4)]
self.assert_fix(
[
"from ... import \\\n",
" lib1, lib2, lib3, \\\n",
" lib4, lib5, lib6\n",
],
"from ... import \\\n" " lib2, lib5, lib6\n",
)
# Example m3 (isort)
self.unused = [".parent.lib" + str(x) for x in (1, 3, 4)]
self.assert_fix(
[
"from .parent import (\n",
" lib1,\n",
" lib2,\n",
" lib3,\n",
" lib4,\n",
" lib5\n",
")\n",
],
"from .parent import (\n" " lib2,\n" " lib5\n" ")\n",
)
def test_fix_without_from(self):
self.unused = ["lib" + str(x) for x in (1, 3, 4)]
# Multiline but not "from"
self.assert_fix(
[
"import \\\n",
" lib1, lib2, lib3 \\\n",
" ,lib4, lib5, lib6\n",
],
"import \\\n" " lib2, lib5, lib6\n",
)
self.assert_fix(
[
"import lib1, lib2, lib3, \\\n",
" lib4, lib5, lib6\n",
],
"import lib2, lib5, lib6\n",
)
# Problematic example without "from"
self.assert_fix(
[
"import \\\n",
" lib1,\\\n",
" lib2, \\\n",
" libA\\\n", # used import with no commas
" ,lib3, \\\n", # leading and trailing commas with unused
" libB, \\\n",
" \\ \n", # empty line with continuation
" lib4\\\n", # unused import with comment
"\n",
],
"import \\\n" " lib2,\\\n" " libA, \\\n" " libB\\\n" "\n",
)
self.unused = [f"lib{x}.x.y.z" for x in (1, 3, 4)]
self.assert_fix(
[
"import \\\n",
" lib1.x.y.z \\",
" , \\\n",
" lib2.x.y.z \\\n",
" , \\\n",
" lib3.x.y.z \\\n",
" , \\\n",
" lib4.x.y.z \\\n",
" , \\\n",
" lib5.x.y.z\n",
],
"import \\\n" " lib2.x.y.z \\" " , \\\n" " lib5.x.y.z\n",
)
def test_give_up(self):
# Semicolon
self.unused = ["lib" + str(x) for x in (1, 3, 4)]
self.assert_fix(
[
"import \\\n",
" lib1, lib2, lib3, \\\n",
" lib4, lib5; import lib6\n",
],
"import \\\n" " lib1, lib2, lib3, \\\n" " lib4, lib5; import lib6\n",
)
# Comments
self.unused = [".lib" + str(x) for x in (1, 3, 4)]
self.assert_fix(
[
"from . import ( # comment\n",
" lib1,\\\n", # only unused + line continuation
" lib2, \n",
" libA\n", # used import with no commas
" ,lib3, \n", # leading and trailing commas + unused import
" libB, \n",
" \\ \n", # empty line with continuation
" lib4, # noqa \n", # unused import with comment
") ; import sys\n",
],
"from . import ( # comment\n"
" lib1,\\\n"
" lib2, \n"
" libA\n"
" ,lib3, \n"
" libB, \n"
" \\ \n"
" lib4, # noqa \n"
") ; import sys\n",
)
def test_just_one_import_used(self):
self.unused = ["lib2"]
self.assert_fix(
[
"import \\\n",
" lib1\n",
],
"import \\\n" " lib1\n",
)
self.assert_fix(
[
"import \\\n",
" lib2\n",
],
"pass\n",
)
# Example from issue #8
self.unused = ["re.subn"]
self.assert_fix(
[
"\tfrom re import (subn)\n",
],
"\tpass\n",
)
def test_just_one_import_left(self):
# Examples from issue #8
self.unused = ["math.sqrt"]
self.assert_fix(
[
"from math import (\n",
" sqrt,\n",
" log\n",
" )\n",
],
"from math import (\n" " log\n" " )\n",
)
self.unused = ["module.b"]
self.assert_fix(
[
"from module import (a, b)\n",
],
"from module import a\n",
)
self.assert_fix(
[
"from module import (a,\n",
" b)\n",
],
"from module import a\n",
)
self.unused = []
self.assert_fix(
[
"from re import (subn)\n",
],
"from re import (subn)\n",
)
def test_no_empty_imports(self):
self.unused = ["lib" + str(x) for x in (1, 3, 4)]
self.assert_fix(
[
"import \\\n",
" lib1, lib3, \\\n",
" lib4 \n",
],
"pass \n",
)
# Indented parenthesized block
self.unused = [".parent.lib" + str(x) for x in (1, 3, 4)]
self.assert_fix(
[
"\t\tfrom .parent import (\n",
" lib1,\n",
" lib3,\n",
" lib4,\n",
")\n",
],
"\t\tpass\n",
)
def test_without_remove_all(self):
self.unused = ["lib" + str(x) for x in (1, 3, 4)]
self.assert_fix(
[
"import \\\n",
" lib1,\\\n",
" lib3,\\\n",
" lib4\n",
],
"import \\\n" " lib1,\\\n" " lib3,\\\n" " lib4\n",
remove_all=False,
)
self.unused += ["os.path." + x for x in ("dirname", "isdir", "join")]
self.assert_fix(
[
"from os.path import (\n",
" dirname,\n",
" isdir,\n",
" join,\n",
")\n",
],
"pass\n",
remove_all=False,
)
self.assert_fix(
[
"import \\\n",
" os.path.dirname, \\\n",
" lib1, \\\n",
" lib3\n",
],
"import \\\n" " lib1, \\\n" " lib3\n",
remove_all=False,
)
class ConfigFileTest(unittest.TestCase):
def setUp(self):
self.tmpdir = tempfile.mkdtemp(prefix="autoflake.")
def tearDown(self):
if self.tmpdir is not None:
shutil.rmtree(self.tmpdir)
self.tmpdir = None
def effective_path(self, path, is_file=True):
path = os.path.normpath(path)
if os.path.isabs(path):
raise ValueError("Should not create an absolute test path")
effective_path = os.path.sep.join([self.tmpdir, path])
if not effective_path.startswith(
f"{self.tmpdir}{os.path.sep}",
) and (effective_path != self.tmpdir or is_file):
raise ValueError("Should create a path within the tmp dir only")
return effective_path
def create_dir(self, path):
effective_path = self.effective_path(path, False)
if sys.version_info >= (3, 2, 0):
os.makedirs(effective_path, exist_ok=True)
else:
if os.path.exists(effective_path):
return
try:
os.mkdir(effective_path)
except OSError:
parent = os.path.split(path)[0]
if not parent:
raise
self.create_dir(parent)
os.mkdir(effective_path)
def create_file(self, path, contents=""):
effective_path = self.effective_path(path)
self.create_dir(os.path.split(path)[0])
with open(effective_path, "w") as f:
f.write(contents)
def with_defaults(self, **kwargs):
return {
"check": False,
"check_diff": False,
"expand_star_imports": False,
"ignore_init_module_imports": False,
"ignore_pass_after_docstring": False,
"ignore_pass_statements": False,
"in_place": False,
"quiet": False,
"recursive": False,
"remove_all_unused_imports": False,
"remove_duplicate_keys": False,
"remove_rhs_for_unused_variables": False,
"remove_unused_variables": False,
"write_to_stdout": False,
**kwargs,
}
def test_no_config_file(self):
self.create_file("test_me.py")
original_args = {
"files": [self.effective_path("test_me.py")],
}
args, success = autoflake.merge_configuration_file(original_args)
assert success is True
assert args == self.with_defaults(**original_args)
def test_non_nested_pyproject_toml_empty(self):
self.create_file("test_me.py")
self.create_file("pyproject.toml", '[tool.other]\nprop="value"\n')
files = [self.effective_path("test_me.py")]
original_args = {"files": files}
args, success = autoflake.merge_configuration_file(original_args)
assert success is True
assert args == self.with_defaults(**original_args)
def test_non_nested_pyproject_toml_non_empty(self):
self.create_file("test_me.py")
self.create_file(
"pyproject.toml",
"[tool.autoflake]\nexpand-star-imports=true\n",
)
files = [self.effective_path("test_me.py")]
args, success = autoflake.merge_configuration_file({"files": files})
assert success is True
assert args == self.with_defaults(
files=files,
expand_star_imports=True,
)
def test_non_nested_setup_cfg_non_empty(self):
self.create_file("test_me.py")
self.create_file(
"setup.cfg",
"[other]\nexpand-star-imports = yes\n",
)
files = [self.effective_path("test_me.py")]
args, success = autoflake.merge_configuration_file({"files": files})
assert success is True
assert args == self.with_defaults(files=files)
def test_non_nested_setup_cfg_empty(self):
self.create_file("test_me.py")
self.create_file(
"setup.cfg",
"[autoflake]\nexpand-star-imports = yes\n",
)
files = [self.effective_path("test_me.py")]
args, success = autoflake.merge_configuration_file({"files": files})
assert success is True
assert args == self.with_defaults(
files=files,
expand_star_imports=True,
)
def test_nested_file(self):
self.create_file("nested/file/test_me.py")
self.create_file(
"pyproject.toml",
"[tool.autoflake]\nexpand-star-imports=true\n",
)
files = [self.effective_path("nested/file/test_me.py")]
args, success = autoflake.merge_configuration_file({"files": files})
assert success is True
assert args == self.with_defaults(
files=files,
expand_star_imports=True,
)
def test_common_path_nested_file_do_not_load(self):
self.create_file("nested/file/test_me.py")
self.create_file("nested/other/test_me.py")
self.create_file(
"nested/file/pyproject.toml",
"[tool.autoflake]\nexpand-star-imports=true\n",
)
files = [
self.effective_path("nested/file/test_me.py"),
self.effective_path("nested/other/test_me.py"),
]
args, success = autoflake.merge_configuration_file({"files": files})
assert success is True
assert args == self.with_defaults(files=files)
def test_common_path_nested_file_do_load(self):
self.create_file("nested/file/test_me.py")
self.create_file("nested/other/test_me.py")
self.create_file(
"nested/pyproject.toml",
"[tool.autoflake]\nexpand-star-imports=true\n",
)
files = [
self.effective_path("nested/file/test_me.py"),
self.effective_path("nested/other/test_me.py"),
]
args, success = autoflake.merge_configuration_file({"files": files})
assert success is True
assert args == self.with_defaults(
files=files,
expand_star_imports=True,
)
def test_common_path_instead_of_common_prefix(self):
"""Using common prefix would result in a failure."""
self.create_file("nested/file-foo/test_me.py")
self.create_file("nested/file-bar/test_me.py")
self.create_file(
"nested/file/pyproject.toml",
"[tool.autoflake]\nexpand-star-imports=true\n",
)
files = [
self.effective_path("nested/file-foo/test_me.py"),
self.effective_path("nested/file-bar/test_me.py"),
]
args, success = autoflake.merge_configuration_file({"files": files})
assert success is True
assert args == self.with_defaults(files=files)
def test_continue_search_if_no_config_found(self):
self.create_file("nested/test_me.py")
self.create_file(
"nested/pyproject.toml",
'[tool.other]\nprop = "value"\n',
)
self.create_file(
"pyproject.toml",
"[tool.autoflake]\nexpand-star-imports = true\n",
)
files = [self.effective_path("nested/test_me.py")]
args, success = autoflake.merge_configuration_file({"files": files})
assert success is True
assert args == self.with_defaults(
files=files,
expand_star_imports=True,
)
def test_stop_search_if_config_found(self):
self.create_file("nested/test_me.py")
self.create_file(
"nested/pyproject.toml",
"[tool.autoflake]\n",
)
self.create_file(
"pyproject.toml",
"[tool.autoflake]\nexpand-star-imports = true\n",
)
files = [self.effective_path("nested/test_me.py")]
args, success = autoflake.merge_configuration_file({"files": files})
assert success is True
assert args == self.with_defaults(files=files)
def test_config_option(self):
with temporary_file(
suffix=".ini",
contents=("[autoflake]\n" "check = True\n"),
) as temp_config:
self.create_file("test_me.py")
files = [self.effective_path("test_me.py")]
args, success = autoflake.merge_configuration_file(
{
"files": files,
"config_file": temp_config,
},
)
assert success is True
assert args == self.with_defaults(
files=files,
config_file=temp_config,
check=True,
)
def test_load_false(self):
self.create_file("test_me.py")
self.create_file(
"setup.cfg",
"[autoflake]\nexpand-star-imports = no\n",
)
files = [self.effective_path("test_me.py")]
args, success = autoflake.merge_configuration_file({"files": files})
assert success is True
assert args == self.with_defaults(
files=files,
expand_star_imports=False,
)
def test_list_value_pyproject_toml(self):
self.create_file("test_me.py")
self.create_file(
"pyproject.toml",
'[tool.autoflake]\nimports=["my_lib", "other_lib"]\n',
)
files = [self.effective_path("test_me.py")]
args, success = autoflake.merge_configuration_file({"files": files})
assert success is True
assert args == self.with_defaults(
files=files,
imports="my_lib,other_lib",
)
def test_list_value_comma_sep_string_pyproject_toml(self):
self.create_file("test_me.py")
self.create_file(
"pyproject.toml",
'[tool.autoflake]\nimports="my_lib,other_lib"\n',
)
files = [self.effective_path("test_me.py")]
args, success = autoflake.merge_configuration_file({"files": files})
assert success is True
assert args == self.with_defaults(
files=files,
imports="my_lib,other_lib",
)
def test_list_value_setup_cfg(self):
self.create_file("test_me.py")
self.create_file(
"setup.cfg",
"[autoflake]\nimports=my_lib,other_lib\n",
)
files = [self.effective_path("test_me.py")]
args, success = autoflake.merge_configuration_file({"files": files})
assert success is True
assert args == self.with_defaults(
files=files,
imports="my_lib,other_lib",
)
def test_non_bool_value_for_bool_property(self):
self.create_file("test_me.py")
self.create_file(
"pyproject.toml",
'[tool.autoflake]\nexpand-star-imports="invalid"\n',
)
files = [self.effective_path("test_me.py")]
_, success = autoflake.merge_configuration_file({"files": files})
assert success is False
def test_non_bool_value_for_bool_property_in_setup_cfg(self):
self.create_file("test_me.py")
self.create_file(
"setup.cfg",
"[autoflake]\nexpand-star-imports=ok\n",
)
files = [self.effective_path("test_me.py")]
_, success = autoflake.merge_configuration_file({"files": files})
assert success is False
def test_non_list_value_for_list_property(self):
self.create_file("test_me.py")
self.create_file(
"pyproject.toml",
"[tool.autoflake]\nexclude=true\n",
)
files = [self.effective_path("test_me.py")]
_, success = autoflake.merge_configuration_file({"files": files})
assert success is False
def test_merge_with_cli_set_list_property(self):
self.create_file("test_me.py")
self.create_file(
"pyproject.toml",
'[tool.autoflake]\nimports=["my_lib"]\n',
)
files = [self.effective_path("test_me.py")]
args, success = autoflake.merge_configuration_file(
{"files": files, "imports": "other_lib"},
)
assert success is True
assert args == self.with_defaults(
files=files,
imports="my_lib,other_lib",
)
def test_merge_prioritizes_flags(self):
self.create_file("test_me.py")
self.create_file(
"pyproject.toml",
"[tool.autoflake]\ncheck = false\n",
)
files = [self.effective_path("test_me.py")]
flag_args = {
"files": files,
"imports": "other_lib",
"check": True,
}
args, success = autoflake.merge_configuration_file(flag_args)
assert success is True
assert args == self.with_defaults(
files=files,
imports="other_lib",
check=True,