(body: list[ast.stmt], current_module_qn: str)
| 164 | seen_funcs: set[str] = set() |
| 165 | |
| 166 | def walk(body: list[ast.stmt], current_module_qn: str) -> None: |
| 167 | for node in body: |
| 168 | if isinstance(node, ast.ClassDef): |
| 169 | qn = f"{current_module_qn}.{node.name}" |
| 170 | classes.append(StubClass( |
| 171 | qualified_name=qn, |
| 172 | short_name=node.name, |
| 173 | methods=class_methods(node), |
| 174 | bases=base_qns(node, current_module_qn), |
| 175 | )) |
| 176 | elif is_method(node): |
| 177 | name = node.name # type: ignore[attr-defined] |
| 178 | if name.startswith("_") and name not in {"__init__"}: |
| 179 | continue |
| 180 | if name in seen_funcs: |
| 181 | continue |
| 182 | seen_funcs.add(name) |
| 183 | functions.append(StubFunction( |
| 184 | qualified_name=f"{current_module_qn}.{name}", |
| 185 | short_name=name, |
| 186 | module_qn=current_module_qn, |
| 187 | )) |
| 188 | elif isinstance(node, ast.ImportFrom): |
| 189 | # Track `from X import *` for re-export resolution. |
| 190 | if node.module and any(alias.name == "*" for alias in node.names): |
| 191 | star_imports.append(StarReExport(target_module=node.module)) |
| 192 | elif isinstance(node, ast.If): |
| 193 | # Flatten version guards. |
| 194 | walk(node.body, current_module_qn) |
| 195 | walk(node.orelse, current_module_qn) |
| 196 | |
| 197 | walk(tree.body, module_qn) |
| 198 | return ModuleStubs(module_qn=module_qn, classes=classes, functions=functions), star_imports |
no test coverage detected