Skip to content
Merged
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
20 changes: 19 additions & 1 deletion autoflake.py
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,17 @@ def __init__(
"""Receive the same parameters as ``filter_unused_import``."""
self.remove: Iterable[str] = unused_module
self.parenthesized: bool = "(" in line
self.from_, imports = self.IMPORT_RE.split(line, maxsplit=1)
split = self.IMPORT_RE.split(line, maxsplit=1)
if len(split) == 1:
# ``import`` is on a continuation line (e.g. ``from X \<newline>
# import Y``). Treat the whole first line as the ``from``
# fragment and leave imports empty; give_up ensures the statement
# is passed through unchanged.
self.from_, imports = line, ""
self.give_up_no_import_on_first_line: bool = True
else:
self.from_, imports = split
self.give_up_no_import_on_first_line = False
match = self.BASE_RE.search(self.from_)
self.base = match.group(1) if match else None
self.give_up: bool = False
Expand All @@ -401,6 +411,10 @@ def __init__(
# Ignore tricky things like "try: \<new line> import" ...
self.give_up = True

if self.give_up_no_import_on_first_line:
# ``import`` is deferred to a continuation line; cannot filter.
self.give_up = True

self.analyze(line)

PendingFix.__init__(self, imports)
Expand Down Expand Up @@ -470,6 +484,10 @@ def __call__(self, line: str | None = None) -> PendingFix | str:
if not self.is_over(line):
return self
if self.give_up:
if self.give_up_no_import_on_first_line:
# The ``import`` keyword was not on the first line; reconstruct
# verbatim without inserting a spurious ``import``.
return self.from_ + "".join(self.accumulator)
return self.from_ + "import " + "".join(self.accumulator)

return self.fix(self.accumulator)
Expand Down
23 changes: 23 additions & 0 deletions test_autoflake.py
Original file line number Diff line number Diff line change
Expand Up @@ -717,6 +717,29 @@ def test_filter_code_multiline_from_imports(self) -> None:
),
)

def test_filter_code_backslash_continuation_import_on_second_line(
self,
) -> None:
"""Backslash-continuation where 'import' appears on the second line.

``from X \\<newline> import A, B`` is a valid Python multiline
import. autoflake used to crash with ``ValueError: not enough values
to unpack`` because the regex split expected ``import`` on the first
line. The statement must be passed through unchanged (give_up path).
"""
source = "".join(
[
"from ci.zimbeast.test_scripts.framework.test_interrupt.seq_lib \\\n",
" import IntTestSequence, send_int\n",
"\n",
"x = send_int(1)\n",
]
)
self.assertEqual(
source,
"".join(autoflake.filter_code(source, remove_all_unused_imports=True)),
)

def test_filter_code_should_ignore_semicolons(self) -> None:
self.assertEqual(
r"""\
Expand Down
Loading