summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Crosley <timothy.crosley@gmail.com>2020-10-03 01:24:35 -0700
committerTimothy Crosley <timothy.crosley@gmail.com>2020-10-03 01:24:35 -0700
commit5fad3537b0e4eed1f21454f33f7387ac79b2caa8 (patch)
tree8dac26526289cc83a9579623c8795d8545de47e8
parent82d76ef81b90ed213f9ce3f46d3c97e1322025be (diff)
parentfc956a7e01ab9f24488a5a18954ea23ed0e649c2 (diff)
downloadisort-5fad3537b0e4eed1f21454f33f7387ac79b2caa8.tar.gz
Merge branch 'develop' of https://github.com/timothycrosley/isort into issue/1487/improve-handling-of-encoding-errors
-rw-r--r--isort/api.py2
-rw-r--r--isort/core.py11
-rw-r--r--isort/main.py8
-rw-r--r--isort/parse.py18
-rw-r--r--isort/settings.py1
-rw-r--r--tests/unit/test_main.py101
-rw-r--r--tests/unit/test_parse.py1
-rw-r--r--tests/unit/test_regressions.py75
8 files changed, 213 insertions, 4 deletions
diff --git a/isort/api.py b/isort/api.py
index f59bc6d9..6c5876be 100644
--- a/isort/api.py
+++ b/isort/api.py
@@ -210,7 +210,7 @@ def check_stream(
)
printer = create_terminal_printer(color=config.color_output)
if not changed:
- if config.verbose:
+ if config.verbose and not config.only_modified:
printer.success(f"{file_path or ''} Everything Looks Good!")
return True
else:
diff --git a/isort/core.py b/isort/core.py
index 22cba49e..7f4c2c8a 100644
--- a/isort/core.py
+++ b/isort/core.py
@@ -67,6 +67,7 @@ def process(
made_changes: bool = False
stripped_line: str = ""
end_of_file: bool = False
+ verbose_output: List[str] = []
if config.float_to_top:
new_input = ""
@@ -87,6 +88,7 @@ def process(
current += line_separator + line_separator.join(add_imports)
add_imports = []
parsed = parse.file_contents(current, config=config)
+ verbose_output += parsed.verbose_output
extra_space = ""
while current and current[-1] == "\n":
extra_space += "\n"
@@ -325,8 +327,11 @@ def process(
line[len(indent) :] for line in import_section.splitlines(keepends=True)
)
+ parsed_content = parse.file_contents(import_section, config=config)
+ verbose_output += parsed_content.verbose_output
+
sorted_import_section = output.sorted_imports(
- parse.file_contents(import_section, config=config),
+ parsed_content,
_indented_config(config, indent),
extension,
import_type="cimport" if cimports else "import",
@@ -384,6 +389,10 @@ def process(
output_stream.write(new_line)
stripped_line = new_line.strip().split("#")[0]
+ if made_changes and config.only_modified:
+ for output_str in verbose_output:
+ print(output_str)
+
return made_changes
diff --git a/isort/main.py b/isort/main.py
index 841caca5..a8e59f0e 100644
--- a/isort/main.py
+++ b/isort/main.py
@@ -768,6 +768,14 @@ def _build_arg_parser() -> argparse.ArgumentParser:
"Imports are unaltered and keep their relative positions within the different sections.",
)
+ parser.add_argument(
+ "--only-modified",
+ "--om",
+ dest="only_modified",
+ action="store_true",
+ help="Suppresses verbose output for non-modified files.",
+ )
+
return parser
diff --git a/isort/parse.py b/isort/parse.py
index 6f121c6b..9348267c 100644
--- a/isort/parse.py
+++ b/isort/parse.py
@@ -138,6 +138,7 @@ class ParsedContent(NamedTuple):
original_line_count: int
line_separator: str
sections: Any
+ verbose_output: List[str]
def file_contents(contents: str, config: Config = DEFAULT_CONFIG) -> ParsedContent:
@@ -163,6 +164,8 @@ def file_contents(contents: str, config: Config = DEFAULT_CONFIG) -> ParsedConte
"from": defaultdict(list),
}
imports: OrderedDict[str, Dict[str, Any]] = OrderedDict()
+ verbose_output: List[str] = []
+
for section in chain(config.sections, config.forced_separate):
imports[section] = {"straight": OrderedDict(), "from": OrderedDict()}
categorized_comments: CommentsDict = {
@@ -380,8 +383,13 @@ def file_contents(contents: str, config: Config = DEFAULT_CONFIG) -> ParsedConte
if type_of_import == "from":
import_from = just_imports.pop(0)
placed_module = finder(import_from)
- if config.verbose:
+ if config.verbose and not config.only_modified:
print(f"from-type place_module for {import_from} returned {placed_module}")
+
+ elif config.verbose:
+ verbose_output.append(
+ f"from-type place_module for {import_from} returned {placed_module}"
+ )
if placed_module == "":
warn(
f"could not place module {import_from} of line {line} --"
@@ -469,8 +477,13 @@ def file_contents(contents: str, config: Config = DEFAULT_CONFIG) -> ParsedConte
categorized_comments["above"]["straight"].get(module, [])
)
placed_module = finder(module)
- if config.verbose:
+ if config.verbose and not config.only_modified:
print(f"else-type place_module for {module} returned {placed_module}")
+
+ elif config.verbose:
+ verbose_output.append(
+ f"else-type place_module for {module} returned {placed_module}"
+ )
if placed_module == "":
warn(
f"could not place module {module} of line {line} --"
@@ -497,4 +510,5 @@ def file_contents(contents: str, config: Config = DEFAULT_CONFIG) -> ParsedConte
original_line_count=original_line_count,
line_separator=line_separator,
sections=config.sections,
+ verbose_output=verbose_output,
)
diff --git a/isort/settings.py b/isort/settings.py
index a4e5905a..937e6e06 100644
--- a/isort/settings.py
+++ b/isort/settings.py
@@ -199,6 +199,7 @@ class _Config:
variables: FrozenSet[str] = frozenset()
dedup_headings: bool = False
only_sections: bool = False
+ only_modified: bool = False
def __post_init__(self):
py_version = self.py_version
diff --git a/tests/unit/test_main.py b/tests/unit/test_main.py
index 9c2da466..3fb75ed6 100644
--- a/tests/unit/test_main.py
+++ b/tests/unit/test_main.py
@@ -70,6 +70,8 @@ def test_parse_args():
assert main.parse_args(["--dt"]) == {"order_by_type": False}
assert main.parse_args(["--only-sections"]) == {"only_sections": True}
assert main.parse_args(["--os"]) == {"only_sections": True}
+ assert main.parse_args(["--om"]) == {"only_modified": True}
+ assert main.parse_args(["--only-modified"]) == {"only_modified": True}
def test_ascii_art(capsys):
@@ -750,4 +752,103 @@ __revision__ = 'יייי'
main.main([str(tmp_file), str(normal_file), "--verbose"])
out, error = capsys.readouterr()
+ # ensures that only-modified flag works with stdin
+ input_content = TextIOWrapper(
+ BytesIO(
+ b"""
+import a
+import b
+"""
+ )
+ )
+
+ main.main(["-", "--verbose", "--only-modified"], stdin=input_content)
+ out, error = capsys.readouterr()
+
+ assert "else-type place_module for a returned THIRDPARTY" not in out
+ assert "else-type place_module for b returned THIRDPARTY" not in out
+
+
+def test_only_modified_flag(tmpdir, capsys):
+ # ensures there is no verbose output for correct files with only-modified flag
+
+ file1 = tmpdir.join("file1.py")
+ file1.write(
+ """
+import a
+import b
+"""
+ )
+
+ file2 = tmpdir.join("file2.py")
+ file2.write(
+ """
+import math
+
+import pandas as pd
+"""
+ )
+
+ main.main([str(file1), str(file2), "--verbose", "--only-modified"])
+ out, error = capsys.readouterr()
+
+ assert (
+ out
+ == f"""
+ _ _
+ (_) ___ ___ _ __| |_
+ | |/ _/ / _ \\/ '__ _/
+ | |\\__ \\/\\_\\/| | | |_
+ |_|\\___/\\___/\\_/ \\_/
+
+ isort your imports, so you don't have to.
+
+ VERSION {__version__}
+
+"""
+ )
+
+ assert not error
+
+ # ensures that verbose output is only for modified file(s) with only-modified flag
+
+ file3 = tmpdir.join("file3.py")
+ file3.write(
+ """
+import sys
+import os
+"""
+ )
+
+ main.main([str(file1), str(file2), str(file3), "--verbose", "--only-modified"])
+ out, error = capsys.readouterr()
+
+ assert "else-type place_module for sys returned STDLIB" in out
+ assert "else-type place_module for os returned STDLIB" in out
+ assert "else-type place_module for math returned STDLIB" not in out
+ assert "else-type place_module for pandas returned THIRDPARTY" not in out
+
+ assert not error
+
+ # ensures that the behaviour is consistent for check flag with only-modified flag
+
+ main.main([str(file1), str(file2), "--check-only", "--verbose", "--only-modified"])
+ out, error = capsys.readouterr()
+
+ assert (
+ out
+ == f"""
+ _ _
+ (_) ___ ___ _ __| |_
+ | |/ _/ / _ \\/ '__ _/
+ | |\\__ \\/\\_\\/| | | |_
+ |_|\\___/\\___/\\_/ \\_/
+
+ isort your imports, so you don't have to.
+
+ VERSION {__version__}
+
+"""
+ )
+
assert not error
diff --git a/tests/unit/test_parse.py b/tests/unit/test_parse.py
index 98183617..0becac90 100644
--- a/tests/unit/test_parse.py
+++ b/tests/unit/test_parse.py
@@ -37,6 +37,7 @@ def test_file_contents():
original_line_count,
_,
_,
+ _,
) = parse.file_contents(TEST_CONTENTS, config=Config(default_section=""))
assert "\n".join(in_lines) == TEST_CONTENTS
assert "import" not in "\n".join(out_lines)
diff --git a/tests/unit/test_regressions.py b/tests/unit/test_regressions.py
index 5dc2fc81..75759522 100644
--- a/tests/unit/test_regressions.py
+++ b/tests/unit/test_regressions.py
@@ -716,6 +716,81 @@ import os
)
+def test_isort_float_to_top_with_sort_on_off_tests():
+ """Characterization test for current behaviour of float-to-top on isort: on/off sections.
+ - imports in isort:off sections stay where they are
+ - imports in isort:on sections float up, but to the top of the isort:on section (not the
+ top of the file)"""
+ assert (
+ isort.code(
+ """
+def foo():
+ pass
+
+import a
+
+# isort: off
+import stays_in_section
+
+x = 1
+
+import stays_in_place
+
+# isort: on
+
+def bar():
+ pass
+
+import floats_to_top_of_section
+
+def baz():
+ pass
+""",
+ float_to_top=True,
+ )
+ == """import a
+
+
+def foo():
+ pass
+
+# isort: off
+import stays_in_section
+
+x = 1
+
+import stays_in_place
+
+# isort: on
+import floats_to_top_of_section
+
+
+def bar():
+ pass
+
+
+def baz():
+ pass
+"""
+ )
+
+ to_sort = """# isort: off
+
+def foo():
+ pass
+
+import stays_in_place
+import no_float_to_to_top
+import no_ordering
+
+def bar():
+ pass
+"""
+
+ # No changes if isort is off
+ assert isort.code(to_sort, float_to_top=True) == to_sort
+
+
def test_isort_doesnt_float_to_top_correctly_when_imports_not_at_top_issue_1382():
"""isort should float existing imports to the top, if they are currently below the top.
See: https://github.com/PyCQA/isort/issues/1382