Skip to content

Commit b0f2dab

Browse files
authored
Merge pull request #2458 from skv0zsneg/issue/1882
Fix edge case of `__future__` import.
2 parents e8c127b + 313797b commit b0f2dab

2 files changed

Lines changed: 74 additions & 1 deletion

File tree

isort/output.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
from .settings import DEFAULT_CONFIG, Config
1313

1414

15+
# Ignore DeepSource cyclomatic complexity check for this function.
16+
# skipcq: PY-R1000
1517
def sorted_imports(
1618
parsed: parse.ParsedContent,
1719
config: Config = DEFAULT_CONFIG,
@@ -88,7 +90,7 @@ def sorted_imports(
8890
lines_between = [""] * (
8991
config.lines_between_types if from_modules and straight_modules else 0
9092
)
91-
if config.from_first:
93+
if config.from_first or section == "FUTURE":
9294
section_output = from_imports + lines_between + straight_imports
9395
else:
9496
section_output = straight_imports + lines_between + from_imports

tests/unit/test_isort.py

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5640,3 +5640,74 @@ def test_noqa_multiline_hanging_indent() -> None:
56405640
)
56415641
output = isort.code(test_input, line_length=120, multi_line_output=WrapModes.HANGING_INDENT)
56425642
assert output == test_input
5643+
5644+
5645+
@pytest.mark.parametrize(
5646+
(
5647+
"actual_imports",
5648+
"expected_sort",
5649+
),
5650+
[
5651+
(
5652+
("from __future__ import annotations\nimport __future__\n"),
5653+
("from __future__ import annotations\nimport __future__\n"),
5654+
),
5655+
(
5656+
(
5657+
"import __future__\n\n"
5658+
"from __future__ import generator_stop\n"
5659+
"from __future__ import annotations\n\n"
5660+
"from concurrent.futures import ThreadPoolExecutor\n\n"
5661+
),
5662+
(
5663+
"from __future__ import annotations, generator_stop\n"
5664+
"import __future__\n\n"
5665+
"from concurrent.futures import ThreadPoolExecutor\n"
5666+
),
5667+
),
5668+
(
5669+
("from __future__ import annotations\nimport sys\n"),
5670+
("from __future__ import annotations\n\nimport sys\n"),
5671+
),
5672+
(("import __future__\nimport sys\n"), ("import __future__\n\nimport sys\n")),
5673+
(
5674+
("import __future__ as future\nfrom __future__ import annotations\n"),
5675+
("from __future__ import annotations\nimport __future__ as future\n"),
5676+
),
5677+
(
5678+
("# Copyright 2026\nimport __future__\nfrom __future__ import annotations\n"),
5679+
("# Copyright 2026\nfrom __future__ import annotations\nimport __future__\n"),
5680+
),
5681+
(
5682+
("import __future__\nfrom __future__ import *\n"),
5683+
("from __future__ import *\nimport __future__\n"),
5684+
),
5685+
(
5686+
(
5687+
"from __future__ import annotations\n"
5688+
"import __future__\n"
5689+
"from __future__ import annotations\n"
5690+
),
5691+
("from __future__ import annotations\nimport __future__\n"),
5692+
),
5693+
(
5694+
(
5695+
"import sys\n"
5696+
"from __future__ import annotations\n"
5697+
"import os\n"
5698+
"import __future__\n"
5699+
"from pathlib import Path\n"
5700+
),
5701+
(
5702+
"from __future__ import annotations\n"
5703+
"import __future__\n\n"
5704+
"import os\n"
5705+
"import sys\n"
5706+
"from pathlib import Path\n"
5707+
),
5708+
),
5709+
],
5710+
)
5711+
def test_dunder_future_import(actual_imports: str, expected_sort: str) -> None:
5712+
output = isort.code(actual_imports)
5713+
assert output == expected_sort

0 commit comments

Comments
 (0)