summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Edmund Crosley <timothy.crosley@gmail.com>2019-12-28 02:25:30 -0800
committerGitHub <noreply@github.com>2019-12-28 02:25:30 -0800
commit4edfd1d6c8ba741ac24594ff95847451b94db293 (patch)
tree67857c3e7fabd9df2587f8f4076d1836b639c86e
parent3f0efe271aa57016ad3c5492fae2a5e47a9d686b (diff)
parentd5a9bf6710270f76573d018de73c7f06e4db9852 (diff)
downloadisort-4edfd1d6c8ba741ac24594ff95847451b94db293.tar.gz
Merge pull request #1074 from timothycrosley/feature/isort-skip-support
Feature/isort skip support
-rw-r--r--isort/api.py24
-rw-r--r--isort/parse.py8
-rw-r--r--isort/settings.py5
-rw-r--r--tests/test_isort.py45
4 files changed, 64 insertions, 18 deletions
diff --git a/isort/api.py b/isort/api.py
index c53fe98a..8d435b21 100644
--- a/isort/api.py
+++ b/isort/api.py
@@ -15,7 +15,7 @@ from .exceptions import (
)
from .format import format_natural, remove_whitespace, show_unified_diff
from .io import File
-from .settings import DEFAULT_CONFIG, FILE_SKIP_COMMENT, Config
+from .settings import DEFAULT_CONFIG, FILE_SKIP_COMMENTS, Config
IMPORT_START_IDENTIFIERS = ("from ", "from.import", "import ", "import*")
COMMENT_INDICATORS = ('"""', "'''", "'", '"', "#")
@@ -54,12 +54,13 @@ def sorted_imports(
config = _config(config=config, **config_kwargs)
content_source = str(file_path or "Passed in content")
if not disregard_skip:
- if FILE_SKIP_COMMENT in file_contents:
- raise FileSkipComment(content_source)
-
- elif file_path and config.is_skipped(file_path):
+ if file_path and config.is_skipped(file_path):
raise FileSkipSetting(content_source)
+ for file_skip_comment in FILE_SKIP_COMMENTS:
+ if file_skip_comment in file_contents:
+ raise FileSkipComment(content_source)
+
if config.atomic:
try:
compile(file_contents, content_source, "exec", 0, 1)
@@ -156,6 +157,7 @@ def sort_imports(
first_import_section: bool = True
section_comments = [f"# {heading}" for heading in config.import_headings.values()]
indent: str = ""
+ isort_off: bool = False
for index, line in enumerate(chain(input_stream, (None,))):
if line is None:
@@ -207,10 +209,18 @@ def sort_imports(
break
char_index += 1
- not_imports = bool(in_quote) or in_top_comment
+ not_imports = bool(in_quote) or in_top_comment or isort_off
if not (in_quote or in_top_comment):
stripped_line = line.strip()
- if not stripped_line or stripped_line.startswith("#"):
+ if isort_off:
+ if stripped_line == "# isort: on":
+ isort_off = False
+ elif stripped_line == "# isort: off":
+ not_imports = True
+ isort_off = True
+ elif stripped_line == "# isort: split":
+ not_imports = True
+ elif not stripped_line or stripped_line.startswith("#"):
import_section += line
elif stripped_line.startswith(IMPORT_START_IDENTIFIERS):
contains_imports = True
diff --git a/isort/parse.py b/isort/parse.py
index a87461ff..6089c08b 100644
--- a/isort/parse.py
+++ b/isort/parse.py
@@ -54,7 +54,7 @@ def _normalize_line(raw_line: str) -> Tuple[str, str]:
def import_type(line: str) -> Optional[str]:
"""If the current line is an import line it will return its type (from or straight)"""
- if "isort:skip" in line or "NOQA" in line:
+ if "isort:skip" in line or "isort: skip" in line or "NOQA" in line:
return None
elif line.startswith("import "):
return "straight"
@@ -174,6 +174,10 @@ def file_contents(contents: str, config: Config = DEFAULT_CONFIG) -> ParsedConte
section = line.split("isort:imports-")[-1].split()[0].upper()
place_imports[section] = []
import_placements[line] = section
+ elif "isort: imports-" in line and line.startswith("#"):
+ section = line.split("isort: imports-")[-1].split()[0].upper()
+ place_imports[section] = []
+ import_placements[line] = section
if skipping_line:
out_lines.append(line)
@@ -325,6 +329,7 @@ def file_contents(contents: str, config: Config = DEFAULT_CONFIG) -> ParsedConte
and not last.endswith('"""')
and not last.endswith("'''")
and "isort:imports-" not in last
+ and "isort: imports-" not in last
):
categorized_comments["above"]["from"].setdefault(import_from, []).insert(
0, out_lines.pop(-1)
@@ -361,6 +366,7 @@ def file_contents(contents: str, config: Config = DEFAULT_CONFIG) -> ParsedConte
and not last.endswith('"""')
and not last.endswith("'''")
and "isort:imports-" not in last
+ and "isort: imports-" not in last
):
categorized_comments["above"]["straight"].setdefault(module, []).insert(
0, out_lines.pop(-1)
diff --git a/isort/settings.py b/isort/settings.py
index 1bdc35cb..ed5e4a51 100644
--- a/isort/settings.py
+++ b/isort/settings.py
@@ -55,7 +55,10 @@ try:
except ImportError:
appdirs = None
-FILE_SKIP_COMMENT: str = ("isort:" + "skip_file") # Concatenated to avoid this file being skipped
+FILE_SKIP_COMMENTS: Tuple[str, ...] = (
+ "isort:" + "skip_file",
+ "isort: " + "skip_file",
+) # Concatenated to avoid this file being skipped
MAX_CONFIG_SEARCH_DEPTH: int = 25 # The number of parent directories to for a config file within
STOP_CONFIG_SEARCH_ON_DIRS: Tuple[str, ...] = (".git", ".hg")
VALID_PY_TARGETS: Tuple[str, ...] = tuple(
diff --git a/tests/test_isort.py b/tests/test_isort.py
index 40b22bb2..e5072b0f 100644
--- a/tests/test_isort.py
+++ b/tests/test_isort.py
@@ -641,7 +641,7 @@ def test_skip() -> None:
"import myproject\n"
"import django\n"
"print('hey')\n"
- "import sys # isort:skip this import needs to be placed here\n\n\n\n\n\n\n"
+ "import sys # isort: skip this import needs to be placed here\n\n\n\n\n\n\n"
)
test_output = SortImports(file_contents=test_input, known_third_party=["django"]).output
@@ -651,7 +651,7 @@ def test_skip() -> None:
"import myproject\n"
"\n"
"print('hey')\n"
- "import sys # isort:skip this import needs to be placed here\n"
+ "import sys # isort: skip this import needs to be placed here\n"
)
@@ -668,7 +668,7 @@ def test_skip_with_file_name() -> None:
def test_skip_within_file() -> None:
"""Ensure skipping a whole file works."""
- test_input = "# isort:skip_file\nimport django\nimport myproject\n"
+ test_input = "# isort: skip_file\nimport django\nimport myproject\n"
sort_imports = SortImports(file_contents=test_input, known_third_party=["django"])
assert sort_imports.skipped
assert sort_imports.output == ""
@@ -1624,19 +1624,19 @@ def test_place_comments() -> None:
"import myproject.test\n"
"import django.settings\n"
"\n"
- "# isort:imports-thirdparty\n"
- "# isort:imports-firstparty\n"
- "# isort:imports-stdlib\n"
+ "# isort: imports-thirdparty\n"
+ "# isort: imports-firstparty\n"
+ "# isort: imports-stdlib\n"
"\n"
)
expected_output = (
- "\n# isort:imports-thirdparty\n"
+ "\n# isort: imports-thirdparty\n"
"import django.settings\n"
"\n"
- "# isort:imports-firstparty\n"
+ "# isort: imports-firstparty\n"
"import myproject.test\n"
"\n"
- "# isort:imports-stdlib\n"
+ "# isort: imports-stdlib\n"
"import os\n"
"import sys\n"
)
@@ -4186,3 +4186,30 @@ def test_isort_nested_imports() -> None:
return True
"""
)
+
+
+def test_isort_off() -> None:
+ """Test that isort can be turned on and off at will using comments"""
+ test_input = """import os
+
+# isort: off
+import sys
+import os
+# isort: on
+
+from . import local
+"""
+ assert SortImports(file_contents=test_input).output == test_input
+
+
+def test_isort_split() -> None:
+ """Test the ability to split isort import sections"""
+ test_input = """import os
+import sys
+
+# isort: split
+
+import os
+import sys
+"""
+ assert SortImports(file_contents=test_input).output == test_input