summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimothy Edmund Crosley <timothy.crosley@gmail.com>2019-12-26 23:00:18 -0800
committerGitHub <noreply@github.com>2019-12-26 23:00:18 -0800
commit3f0efe271aa57016ad3c5492fae2a5e47a9d686b (patch)
tree5b530701b351d78389e204e09c194a95825319ae
parentef8046c69bc98cca2b581af976a33beddc0e43c4 (diff)
parent6009a180237aa9ba070cb0b14178b83d457e6069 (diff)
downloadisort-3f0efe271aa57016ad3c5492fae2a5e47a9d686b.tar.gz
Merge pull request #1073 from timothycrosley/feature/nested-import-support
Feature/nested import support
-rw-r--r--isort/_future/__init__.py1
-rw-r--r--isort/api.py36
-rw-r--r--isort/finders.py3
-rw-r--r--isort/settings.py1
-rw-r--r--tests/test_isort.py29
5 files changed, 61 insertions, 9 deletions
diff --git a/isort/_future/__init__.py b/isort/_future/__init__.py
index 9f5e9d18..4d9ef4b7 100644
--- a/isort/_future/__init__.py
+++ b/isort/_future/__init__.py
@@ -2,6 +2,7 @@ import sys
if sys.version_info.major <= 3 and sys.version_info.minor <= 6:
from . import _dataclasses as dataclasses # type: ignore
+
else:
import dataclasses # type: ignore
diff --git a/isort/api.py b/isort/api.py
index 4c6bc949..c53fe98a 100644
--- a/isort/api.py
+++ b/isort/api.py
@@ -1,4 +1,5 @@
import re
+import textwrap
from io import StringIO
from itertools import chain
from pathlib import Path
@@ -154,6 +155,7 @@ def sort_imports(
in_top_comment: bool = False
first_import_section: bool = True
section_comments = [f"# {heading}" for heading in config.import_headings.values()]
+ indent: str = ""
for index, line in enumerate(chain(input_stream, (None,))):
if line is None:
@@ -171,7 +173,7 @@ def sort_imports(
stripped_line = line.strip()
if (
(index == 0 or (index == 1 and not contains_imports))
- and line.startswith("#")
+ and stripped_line.startswith("#")
and stripped_line not in section_comments
):
in_top_comment = True
@@ -180,7 +182,7 @@ def sort_imports(
in_top_comment = False
first_comment_index_end = index - 1
- if not line.startswith("#") and '"' in line or "'" in line:
+ if not stripped_line.startswith("#") and '"' in line or "'" in line:
char_index = 0
if first_comment_index_start == -1 and (
line.startswith('"') or line.startswith("'")
@@ -211,6 +213,9 @@ def sort_imports(
if not stripped_line or stripped_line.startswith("#"):
import_section += line
elif stripped_line.startswith(IMPORT_START_IDENTIFIERS):
+ contains_imports = True
+
+ indent = line[: -len(line.lstrip())]
import_section += line
while stripped_line.endswith("\\") or (
"(" in stripped_line and ")" not in stripped_line
@@ -225,8 +230,6 @@ def sort_imports(
line = input_stream.readline()
stripped_line = line.strip().split("#")[0]
import_section += line
-
- contains_imports = True
else:
not_imports = True
@@ -243,12 +246,13 @@ def sort_imports(
add_imports = []
if import_section:
- if add_imports:
+ if add_imports and not indent:
import_section += line_separator.join(add_imports) + line_separator
contains_imports = True
add_imports = []
- import_section += line
+ if not indent:
+ import_section += line
if not contains_imports:
output_stream.write(import_section)
else:
@@ -257,11 +261,25 @@ def sort_imports(
).startswith(COMMENT_INDICATORS):
import_section = import_section.lstrip(line_separator)
first_import_section = False
- output_stream.write(
- output.sorted_imports(
- parse.file_contents(import_section, config=config), config, extension
+
+ if indent:
+ import_section = line_separator.join(
+ line.lstrip() for line in import_section.split(line_separator)
)
+ sorted_import_section = output.sorted_imports(
+ parse.file_contents(import_section, config=config), config, extension
)
+ if indent:
+ sorted_import_section = (
+ textwrap.indent(sorted_import_section, indent) + line_separator
+ )
+
+ output_stream.write(sorted_import_section)
+
+ if indent:
+ output_stream.write(line)
+ indent = ""
+
contains_imports = False
import_section = ""
else:
diff --git a/isort/finders.py b/isort/finders.py
index d63cc94b..5a7c74a7 100644
--- a/isort/finders.py
+++ b/isort/finders.py
@@ -30,16 +30,19 @@ from .utils import chdir, exists_case_sensitive
try:
from pipreqs import pipreqs
+
except ImportError:
pipreqs = None
try:
from pip_api import parse_requirements
+
except ImportError:
parse_requirements = None
try:
from requirementslib import Pipfile
+
except ImportError:
Pipfile = None
diff --git a/isort/settings.py b/isort/settings.py
index 607c67b6..1bdc35cb 100644
--- a/isort/settings.py
+++ b/isort/settings.py
@@ -43,6 +43,7 @@ from .wrap_modes import from_string as wrap_mode_from_string
try:
import toml
+
except ImportError:
toml = None # type: ignore
diff --git a/tests/test_isort.py b/tests/test_isort.py
index 4e3a0332..40b22bb2 100644
--- a/tests/test_isort.py
+++ b/tests/test_isort.py
@@ -2922,6 +2922,7 @@ def test_to_ensure_importing_from_imports_module_works_issue_662() -> None:
"@wraps(fun)\n"
"def __inner(*args, **kwargs):\n"
" from .imports import qualname\n"
+ "\n"
" warn(description=description or qualname(fun), deprecation=deprecation, "
"removal=removal)\n"
)
@@ -4157,3 +4158,31 @@ def test_isort_with_single_character_import() -> None:
"""
test_input = "from django.db.models import CASCADE, SET_NULL, Q\n"
assert SortImports(file_contents=test_input).output == test_input
+
+
+def test_isort_nested_imports() -> None:
+ """Ensure imports in a nested block get sorted correctly"""
+ test_input = """
+ def import_test():
+ import sys
+ import os
+
+ # my imports
+ from . import def
+ from . import abc
+
+ return True
+ """
+ assert (
+ SortImports(file_contents=test_input).output
+ == """
+ def import_test():
+ import os
+ import sys
+
+ # my imports
+ from . import abc, def
+
+ return True
+ """
+ )