1010from pathlib import Path
1111from typing import TypeVar , cast
1212
13- from astroid import Call , Const , ImportFrom , Name , NodeNG # type: ignore
13+ from astroid import Call , Const , ImportFrom , Name , NodeNG , Try # type: ignore
1414from astroid .exceptions import AstroidSyntaxError # type: ignore
1515from sqlglot import parse as parse_sql , ParseError as SQLParseError
1616
@@ -482,7 +482,7 @@ def _parse_and_extract_nodes(self) -> tuple[Tree, list[NodeBase], Iterable[Depen
482482 nodes = sorted (nodes , key = lambda node : (node .node .lineno , node .node .col_offset ))
483483 return tree , nodes , problems
484484
485- def _build_graph_from_node (self , base_node : NodeBase ):
485+ def _build_graph_from_node (self , base_node : NodeBase ) -> Iterable [ DependencyProblem ] :
486486 if isinstance (base_node , SysPathChange ):
487487 yield from self ._mutate_path_lookup (base_node )
488488 elif isinstance (base_node , NotebookRunCall ):
@@ -509,14 +509,42 @@ def _build_inherited_context_from_node(self, base_node: NodeBase, child_path: Pa
509509 logger .warning (f"Can't build inherited context for node { NodeBase .__name__ } of type { type (base_node ).__name__ } " )
510510 return InheritedContext (None , False )
511511
512- def _register_import (self , base_node : ImportSource ):
512+ def _register_import (self , base_node : ImportSource ) -> Iterable [ DependencyProblem ] :
513513 prefix = ""
514514 if isinstance (base_node .node , ImportFrom ) and base_node .node .level is not None :
515515 prefix = "." * base_node .node .level
516516 name = base_node .name or ""
517- yield from self ._context .parent .register_import (prefix + name )
517+ problems = self ._context .parent .register_import (prefix + name )
518+ for problem in problems :
519+ prob = self ._filter_import_problem_in_try_except (problem , base_node )
520+ if prob is not None :
521+ yield prob
518522
519- def _register_notebook (self , base_node : NotebookRunCall ):
523+ @classmethod
524+ def _filter_import_problem_in_try_except (
525+ cls , problem : DependencyProblem , base_node : ImportSource
526+ ) -> DependencyProblem | None :
527+ if problem .code != 'import-not-found' :
528+ return problem
529+ # is base_node in a try-except clause ?
530+ node = base_node .node .parent
531+ while node and not isinstance (node , Try ):
532+ node = node .parent
533+ if cls ._is_try_except_import_error (node ):
534+ return None
535+ return problem
536+
537+ @classmethod
538+ def _is_try_except_import_error (cls , node : Try | None ) -> bool :
539+ if not isinstance (node , Try ):
540+ return False
541+ for handler in node .handlers :
542+ if isinstance (handler .type , Name ):
543+ if handler .type .name == "ImportError" :
544+ return True
545+ return False
546+
547+ def _register_notebook (self , base_node : NotebookRunCall ) -> Iterable [DependencyProblem ]:
520548 has_unresolved , paths = base_node .get_notebook_paths (self ._context .session_state )
521549 if has_unresolved :
522550 yield DependencyProblem (
@@ -527,7 +555,7 @@ def _register_notebook(self, base_node: NotebookRunCall):
527555 # notebooks ran via dbutils.notebook.run do not inherit or propagate context
528556 yield from self ._context .parent .register_notebook (Path (path ), False )
529557
530- def _mutate_path_lookup (self , change : SysPathChange ):
558+ def _mutate_path_lookup (self , change : SysPathChange ) -> Iterable [ DependencyProblem ] :
531559 if isinstance (change , UnresolvedPath ):
532560 yield DependencyProblem (
533561 'sys-path-cannot-compute-value' ,
0 commit comments