@@ -86,6 +86,9 @@ def _default_excluded_stdlib() -> set[str]:
8686 "venv" ,
8787 "sqlite3" ,
8888 "tkinter" ,
89+ "__future__" ,
90+ "__main__" ,
91+ "__builtins__" ,
8992 }
9093
9194
@@ -439,27 +442,44 @@ def _extract_imported_modules_from_source(
439442 modules : set [str ] = set ()
440443 try :
441444 tree = ast .parse (source , filename = file_path or "<memory>" )
445+ for node in ast .walk (tree ):
446+ if isinstance (node , ast .Import ):
447+ for alias in node .names :
448+ top = _top_level_module_name (alias .name )
449+ if top :
450+ modules .add (top )
451+ elif isinstance (node , ast .ImportFrom ):
452+ if node .level and node .level > 0 :
453+ rel_root = _resolve_relative_import_root (
454+ file_path , node .level , workspace_dir
455+ )
456+ if rel_root :
457+ modules .add (rel_root )
458+ elif node .module :
459+ top = _top_level_module_name (node .module )
460+ if top :
461+ modules .add (top )
442462 except Exception :
443- return modules
444-
445- for node in ast .walk (tree ):
446- if isinstance (node , ast .Import ):
447- for alias in node .names :
448- top = _top_level_module_name (alias .name )
449- if top :
450- modules .add (top )
451- elif isinstance (node , ast .ImportFrom ):
452- if node .level and node .level > 0 :
453- rel_root = _resolve_relative_import_root (
454- file_path , node .level , workspace_dir
455- )
456- if rel_root :
457- modules .add (rel_root )
458- elif node .module :
459- top = _top_level_module_name (node .module )
463+ # Robust regex-based fallback if AST parsing fails (e.g. syntax error or newer Python version)
464+ # Handle 'import module1, module2 as alias'
465+ import_matches = re .findall (r"^\s*import\s+([\w\.,\s]+)" , source , re .MULTILINE )
466+ for match in import_matches :
467+ for part in match .split ("," ):
468+ # Extract 'module1' from 'module1 as alias'
469+ mod = part .strip ().split (" " )[0 ].strip ()
470+ top = _top_level_module_name (mod )
460471 if top :
461472 modules .add (top )
462473
474+ # Handle 'from module import something'
475+ from_matches = re .findall (
476+ r"^\s*from\s+([\w\.]+)\s+import" , source , re .MULTILINE
477+ )
478+ for mod in from_matches :
479+ top = _top_level_module_name (mod )
480+ if top :
481+ modules .add (top )
482+
463483 dynamic_imports = re .findall (r"__import__\(['\"]([\w\.]+)['\"]\)" , source )
464484 modules .update (
465485 [top for top in (_top_level_module_name (mod ) for mod in dynamic_imports ) if top ]
0 commit comments