Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 28 additions & 19 deletions isort/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -403,26 +403,30 @@ def _with_from_imports(

if not config.only_sections:
output.extend(
with_comments(
from_comments,
wrap.line(
import_start + as_import, parsed.line_separator, config
wrap.line(
with_comments(
from_comments,
import_start + as_import,
removed=config.ignore_comments,
comment_prefix=config.comment_prefix,
),
removed=config.ignore_comments,
comment_prefix=config.comment_prefix,
parsed.line_separator,
config,
)
for as_import in sorting.sort(config, as_imports[from_import])
)

else:
output.extend(
with_comments(
from_comments,
wrap.line(
import_start + as_import, parsed.line_separator, config
wrap.line(
with_comments(
from_comments,
import_start + as_import,
removed=config.ignore_comments,
comment_prefix=config.comment_prefix,
),
removed=config.ignore_comments,
comment_prefix=config.comment_prefix,
parsed.line_separator,
config,
)
for as_import in as_imports[from_import]
)
Expand Down Expand Up @@ -518,6 +522,8 @@ def _with_from_imports(
)
if opening_comment:
lines[0] += opening_comment
if config.multi_line_output == wrap.Modes.NOQA: # type: ignore[attr-defined] # noqa: E501
lines[0] = wrap.line(lines[0], parsed.line_separator, config)
output.append(parsed.line_separator.join(lines))
else:
output.append(
Expand Down Expand Up @@ -719,13 +725,15 @@ def _with_straight_imports(
if inline_comments:
combined_inline_comments = " ".join(c for c in inline_comments if c)
if combined_inline_comments:
output.append(
line_content = (
f"{import_type} {combined_straight_imports} # {combined_inline_comments}"
)
else:
output.append(f"{import_type} {combined_straight_imports} #")
line_content = f"{import_type} {combined_straight_imports} #"
else:
output.append(f"{import_type} {combined_straight_imports}")
line_content = f"{import_type} {combined_straight_imports}"

output.append(wrap.line(line_content, parsed.line_separator, config))

return output

Expand All @@ -747,15 +755,16 @@ def _with_straight_imports(
comments_above = parsed.categorized_comments["above"]["straight"].pop(module, None)
if comments_above:
output.extend(comments_above)
output.extend(
with_comments(
for idef, imodule in import_definition:
line_content = with_comments(
parsed.categorized_comments["straight"].get(imodule),
idef,
removed=config.ignore_comments,
comment_prefix=config.comment_prefix,
)
for idef, imodule in import_definition
)
if config.multi_line_output == wrap.Modes.NOQA: # type: ignore[attr-defined]
line_content = wrap.line(line_content, parsed.line_separator, config)
output.append(line_content)

return output

Expand Down
87 changes: 87 additions & 0 deletions tests/unit/test_regressions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2117,3 +2117,90 @@ def test_noqa_wrap_mode_does_not_accumulate_spaces_with_as_import():
first_pass, multi_line_output=7, force_single_line=True, line_length=40
)
assert second_pass == first_pass


def test_noqa_added_to_long_force_single_line_as_import_with_comment_issue_2093():
"""A long ``as`` import with inline comment must get ``# NOQA`` in NOQA mode.

With ``force_single_line`` an aliased import that carries an inline comment
and overflows the line length must still receive ``# NOQA``. Previously
``with_comments()`` wrapped ``wrap.line()``, so the length check ran on the
import without the comment and ``# NOQA`` was never added.
"""
to_sort = (
"from my_package.my_module import super_long_file_name as super_long_alias"
" # type: ignore\n"
)

first_pass = isort.code(to_sort, multi_line_output=7, force_single_line=True, line_length=40)
assert first_pass == (
"from my_package.my_module import super_long_file_name as super_long_alias"
" # type: ignore # NOQA\n"
)
assert first_pass.count("NOQA") == 1

second_pass = isort.code(
first_pass, multi_line_output=7, force_single_line=True, line_length=40
)
assert second_pass == first_pass


def test_noqa_added_to_long_as_import_with_opening_comment_issue_2093():
"""A long ``as`` import with opening-line comment must get ``# NOQA`` in NOQA mode.

When ``use_parentheses`` is enabled, opening-line comments are kept on the
``from X import (`` line. The ``wrap.line()`` call ran before the comment was
attached, so it saw a short import and never added ``# NOQA``. The fix re-runs
``wrap.line()`` in NOQA mode after the comment is attached.
"""
to_sort = (
"from my_package.my_module import (\n"
" super_long_file_name as super_long_alias # type: ignore\n"
")\n"
)

first_pass = isort.code(to_sort, multi_line_output=7, line_length=40)
assert "# NOQA" in first_pass
assert first_pass.count("NOQA") == 1

second_pass = isort.code(first_pass, multi_line_output=7, line_length=40)
assert second_pass == first_pass


def test_noqa_added_to_long_combined_straight_imports_issue_2093():
"""Long combined straight imports must get ``# NOQA`` in NOQA mode.

With ``combine_straight_imports`` enabled, multiple ``import`` statements
are merged into a single ``import a, b, c, ...`` line. Previously this line
was appended directly without going through ``wrap.line()``, so ``# NOQA``
was never added even when it exceeded the line length.
"""
to_sort = "import a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p\n"

first_pass = isort.code(
to_sort, multi_line_output=7, combine_straight_imports=True, line_length=40
)
assert first_pass == ("import a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p # NOQA\n")
assert first_pass.count("NOQA") == 1

second_pass = isort.code(
first_pass, multi_line_output=7, combine_straight_imports=True, line_length=40
)
assert second_pass == first_pass


def test_noqa_added_to_long_straight_import_issue_2093():
"""Long straight imports must get ``# NOQA`` in NOQA mode.

Straight imports (``import x`` or ``import x as y``) that exceed the line
length were emitted directly without going through ``wrap.line()``, so
``# NOQA`` was never added. The fix wraps each import through ``wrap.line()``.
"""
to_sort = "import aaaa_long_module_name as bbbb_long_alias_name\n"

first_pass = isort.code(to_sort, multi_line_output=7, line_length=40)
assert first_pass == "import aaaa_long_module_name as bbbb_long_alias_name # NOQA\n"
assert first_pass.count("NOQA") == 1

second_pass = isort.code(first_pass, multi_line_output=7, line_length=40)
assert second_pass == first_pass