Skip to content

Commit 3739d65

Browse files
hakancelikdevclaude
andcommitted
Fix nested if statement dispatch not recognized (#294)
Recursively collect import names through nested ast.If blocks in the body branch so that imports inside inner if/else (e.g. TYPE_CHECKING inside a version check) are recognized as part of the outer dispatch pattern. The orelse branch uses flat collection to avoid breaking elif chain handling. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1b8b089 commit 3739d65

4 files changed

Lines changed: 76 additions & 11 deletions

File tree

src/unimport/analyzers/import_statement.py

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,18 @@ def _is_type_checking_block(if_node: ast.If) -> bool:
103103
return True
104104
return False
105105

106+
@staticmethod
107+
def _collect_import_names(nodes: list[ast.stmt], *, recursive: bool = True) -> set[str]:
108+
names: set[str] = set()
109+
for node in nodes:
110+
if isinstance(node, (ast.Import, ast.ImportFrom)):
111+
for alias in node.names:
112+
names.add(alias.asname or alias.name)
113+
elif recursive and isinstance(node, ast.If):
114+
names |= ImportAnalyzer._collect_import_names(node.body)
115+
names |= ImportAnalyzer._collect_import_names(node.orelse)
116+
return names
117+
106118
def visit_If(self, if_node: ast.If) -> None:
107119
if self._is_type_checking_block(if_node):
108120
self._in_type_checking = True
@@ -113,17 +125,9 @@ def visit_If(self, if_node: ast.If) -> None:
113125
self.visit(node)
114126
return
115127

116-
self.if_names = {
117-
name.asname or name.name
118-
for n in filter(lambda node: isinstance(node, (ast.Import, ast.ImportFrom)), if_node.body)
119-
for name in n.names # type: ignore
120-
}
121-
122-
self.orelse_names = {
123-
name.asname or name.name
124-
for n in filter(lambda node: isinstance(node, (ast.Import, ast.ImportFrom)), if_node.orelse)
125-
for name in n.names # type: ignore
126-
}
128+
self.if_names = self._collect_import_names(if_node.body)
129+
130+
self.orelse_names = self._collect_import_names(if_node.orelse, recursive=False)
127131

128132
self.generic_visit(if_node)
129133

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
from typing import Union
2+
3+
from unimport.statement import Import, ImportFrom, Name
4+
5+
__all__ = ["NAMES", "IMPORTS", "UNUSED_IMPORTS"]
6+
7+
8+
NAMES: list[Name] = [
9+
Name(lineno=4, name="sys.version_info", is_all=False),
10+
Name(lineno=5, name="TYPE_CHECKING", is_all=False),
11+
Name(lineno=8, name="Any", is_all=False),
12+
Name(lineno=11, name="Any", is_all=False),
13+
Name(lineno=11, name="Any", is_all=False),
14+
Name(lineno=11, name="Any", is_all=False),
15+
Name(lineno=19, name="print", is_all=False),
16+
Name(lineno=19, name="ForwardRef", is_all=False),
17+
]
18+
IMPORTS: list[Union[Import, ImportFrom]] = [
19+
Import(lineno=1, column=1, name="sys", package="sys"),
20+
ImportFrom(lineno=2, column=1, name="TYPE_CHECKING", package="typing", star=False, suggestions=[]),
21+
ImportFrom(lineno=2, column=2, name="Any", package="typing", star=False, suggestions=[]),
22+
]
23+
UNUSED_IMPORTS: list[Union[Import, ImportFrom]] = []
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import sys
2+
from typing import TYPE_CHECKING, Any
3+
4+
if sys.version_info < (3, 7):
5+
if TYPE_CHECKING:
6+
7+
class ForwardRef:
8+
def __init__(self, arg: Any):
9+
pass
10+
11+
def _eval_type(self, globalns: Any, localns: Any) -> Any:
12+
pass
13+
14+
else:
15+
from typing import _ForwardRef as ForwardRef
16+
else:
17+
from typing import ForwardRef
18+
19+
print(ForwardRef)
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import sys
2+
from typing import TYPE_CHECKING, Any
3+
4+
if sys.version_info < (3, 7):
5+
if TYPE_CHECKING:
6+
7+
class ForwardRef:
8+
def __init__(self, arg: Any):
9+
pass
10+
11+
def _eval_type(self, globalns: Any, localns: Any) -> Any:
12+
pass
13+
14+
else:
15+
from typing import _ForwardRef as ForwardRef
16+
else:
17+
from typing import ForwardRef
18+
19+
print(ForwardRef)

0 commit comments

Comments
 (0)