Skip to content

Commit 67c612c

Browse files
devCodeBuddy Code
authored andcommitted
Wrap overlong 'from ... import *' with a backslash continuation
Instead of leaving the statement untouched (which left a line exceeding line_length), split it at 'import *' and move the wildcard onto a continuation line. Parenthesis-based wrapping is not valid for a wildcard import, so a backslash continuation is the correct way to keep the line valid Python while still respecting line_length when possible. Co-Authored-By: CodeBuddy Code <noreply@codebuddy.ai>
1 parent 2dfb4a1 commit 67c612c

3 files changed

Lines changed: 32 additions & 19 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ Find out more about isort's release policy [here](docs/major_releases/release_po
88

99
### Unreleased
1010

11-
- Fix `from ... import *` statements being word-wrapped into invalid Python when exceeding `line_length` (#2267)
12-
13-
### 8.0.0 February 19 2026
11+
### 8.0.0 February 19 2026
1412

1513
- Removed `--old-finders` and `--magic-placement` flags and `old_finders` configuration option. The legacy finder logic that relied on environment introspection has been removed (#2445) @joao-faria-dev
1614
- Update the `plone` profile to not clash with `black` (#2456) @ale-rt

isort/wrap.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,20 @@ def import_statement(
7070

7171
def line(content: str, line_separator: str, config: Config = DEFAULT_CONFIG) -> str:
7272
"""Returns a line wrapped to the specified line-length, if possible."""
73-
# A ``from ... import *`` statement cannot be split across multiple lines
74-
# because the wildcard ``*`` has no valid continuation. Word-wrapping it
75-
# would move ``import *`` onto a continuation line and produce invalid
76-
# Python. Leave such lines untouched even if they exceed ``line_length``.
73+
# A ``from ... import *`` statement cannot use parenthesis-based wrapping
74+
# because the wildcard ``*`` has no valid continuation in that mode.
75+
# Use a backslash continuation instead so the statement is split across
76+
# lines while remaining valid Python.
7777
# See https://github.com/PyCQA/isort/issues/2267
7878
bare = content.split("#", 1)[0].rstrip()
7979
if bare.startswith("from ") and bare.endswith(" import *"):
80-
return content
80+
if len(content) <= config.line_length:
81+
return content
82+
line_without_comment, _, comment = content.partition("#")
83+
prefix = line_without_comment.rstrip()
84+
comment_suffix = f" #{comment}" if comment else ""
85+
module_path = prefix[: -len(" import *")]
86+
return f"{module_path} import \\{line_separator}{config.indent}*{comment_suffix}"
8187
wrap_mode = config.multi_line_output
8288
if len(content) > config.line_length and wrap_mode != Modes.NOQA:
8389
line_without_comment = content

tests/unit/test_wrap.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -50,27 +50,36 @@ def test_line__comment_with_brackets__expects_unchanged_comment(multi_line_outpu
5050
assert wrap.line(content=content, line_separator="\n", config=config) == expected
5151

5252

53-
def test_line__star_import_not_wrapped():
54-
# A ``from ... import *`` statement cannot be split across lines, so even
55-
# when it exceeds ``line_length`` it must be returned unchanged instead of
56-
# being word-wrapped into invalid Python. See issue #2267.
53+
def test_line__star_import_wrapped_with_backslash():
54+
# A ``from ... import *`` statement cannot use parenthesis-based wrapping,
55+
# so isort falls back to a backslash continuation when the line exceeds
56+
# ``line_length``. See issue #2267.
5757
content = "from very.very.very.very.very.very.very.very.very.very.very.long.line import *"
5858
config = Config(line_length=20)
59-
assert wrap.line(content=content, line_separator="\n", config=config) == content
59+
expected = (
60+
"from very.very.very.very.very.very.very.very.very.very.very.long.line import \\"
61+
"\n *"
62+
)
63+
assert wrap.line(content=content, line_separator="\n", config=config) == expected
6064

6165

62-
def test_line__star_import_with_comment_not_wrapped():
66+
def test_line__star_import_with_comment_wrapped_with_backslash():
6367
content = (
6468
"from very.very.very.very.very.very.very.very.very.very.very.long.line import *"
6569
" # noqa: F401"
6670
)
6771
config = Config(line_length=20)
68-
assert wrap.line(content=content, line_separator="\n", config=config) == content
72+
expected = (
73+
"from very.very.very.very.very.very.very.very.very.very.very.long.line import \\"
74+
"\n * # noqa: F401"
75+
)
76+
assert wrap.line(content=content, line_separator="\n", config=config) == expected
6977

7078

71-
def test_star_import_not_wrapped_end_to_end():
79+
def test_star_import_wrapped_end_to_end():
7280
source = "from very.very.very.very.very.very.very.very.very.very.very.very.long.line import *\n"
7381
result = code(source, line_length=20, force_single_line=True)
74-
# The wildcard import must stay on a single line and remain valid Python.
75-
assert "import *" in result.splitlines()[0]
76-
assert result.strip() == source.strip()
82+
# The wildcard import should be split with a backslash continuation.
83+
lines = result.strip().splitlines()
84+
assert lines[0].rstrip().endswith("import \\")
85+
assert lines[1].strip() == "*"

0 commit comments

Comments
 (0)