@@ -47,8 +47,8 @@ def path(self):
4747 def register_library (self , * libraries : str ) -> list [DependencyProblem ]:
4848 return self ._resolver .register_library (self .path_lookup , * libraries )
4949
50- def register_notebook (self , path : Path ) -> list [DependencyProblem ]:
51- maybe = self ._resolver .resolve_notebook (self .path_lookup , path )
50+ def register_notebook (self , path : Path , inherit_context : bool ) -> list [DependencyProblem ]:
51+ maybe = self ._resolver .resolve_notebook (self .path_lookup , path , inherit_context )
5252 if not maybe .dependency :
5353 return maybe .problems
5454 maybe_graph = self .register_dependency (maybe .dependency )
@@ -199,6 +199,52 @@ def visit(self, visit_node: Callable[[DependencyGraph], bool | None], visited: s
199199 def new_dependency_graph_context (self ):
200200 return DependencyGraphContext (parent = self , path_lookup = self ._path_lookup , session_state = self ._session_state )
201201
202+ def _compute_route (self , root : Path , leaf : Path , visited : set [Path ]) -> list [Dependency ]:
203+ """given 2 files or notebooks root and leaf, compute the list of dependencies that must be traversed
204+ in order to lint the leaf in the context of its parents"""
205+ try :
206+ route = self ._do_compute_route (root , leaf , visited )
207+ return self ._trim_route (route )
208+ except ValueError :
209+ # we only compute routes on graphs so _compute_route can't fail
210+ # but we return an empty route in case it does
211+ return []
212+
213+ def _do_compute_route (self , root : Path , leaf : Path , visited : set [Path ]) -> list [Dependency ]:
214+ maybe = self .locate_dependency (root )
215+ if not maybe .graph :
216+ logger .warning (f"Could not compute route because dependency { root } cannot be located" )
217+ raise ValueError ()
218+ route : list [Dependency ] = []
219+
220+ def do_compute_route (graph : DependencyGraph ) -> bool :
221+ route .append (graph .dependency )
222+ for dependency in graph .local_dependencies :
223+ if dependency .path == leaf :
224+ route .append (dependency )
225+ return True
226+ for dependency in graph .local_dependencies :
227+ sub_route = self ._do_compute_route (dependency .path , leaf , visited )
228+ if len (sub_route ) > 0 :
229+ route .extend (sub_route )
230+ return True
231+ route .pop ()
232+ return False
233+
234+ maybe .graph .visit (do_compute_route , visited )
235+ return route
236+
237+ def _trim_route (self , dependencies : list [Dependency ]) -> list [Dependency ]:
238+ """don't inherit context if dependency is not a file/notebook, or it is loaded via dbutils.notebook.run or via import"""
239+ # filter out intermediate containers
240+ dependencies = list (dependency for dependency in dependencies if dependency .path .is_file ())
241+ # restart when not inheriting context
242+ for i , dependency in enumerate (dependencies ):
243+ if dependency .inherits_context :
244+ continue
245+ return [dependency ] + self ._trim_route (dependencies [i + 1 :])
246+ return dependencies
247+
202248 def __repr__ (self ):
203249 return f"<DependencyGraph { self .path } >"
204250
@@ -212,14 +258,19 @@ class DependencyGraphContext:
212258
213259class Dependency (abc .ABC ):
214260
215- def __init__ (self , loader : DependencyLoader , path : Path ):
261+ def __init__ (self , loader : DependencyLoader , path : Path , inherits_context = True ):
216262 self ._loader = loader
217263 self ._path = path
264+ self ._inherits_context = inherits_context
218265
219266 @property
220267 def path (self ) -> Path :
221268 return self ._path
222269
270+ @property
271+ def inherits_context (self ):
272+ return self ._inherits_context
273+
223274 def __hash__ (self ):
224275 return hash (self .path )
225276
@@ -236,14 +287,12 @@ def __repr__(self):
236287class SourceContainer (abc .ABC ):
237288
238289 @abc .abstractmethod
239- def build_dependency_graph (self , parent : DependencyGraph ) -> list [DependencyProblem ]:
240- """builds a dependency graph from the contents of this container"""
290+ def build_dependency_graph (self , parent : DependencyGraph ) -> list [DependencyProblem ]: ...
241291
242292
243293class DependencyLoader (abc .ABC ):
244294 @abc .abstractmethod
245- def load_dependency (self , path_lookup : PathLookup , dependency : Dependency ) -> SourceContainer | None :
246- """loads a dependency"""
295+ def load_dependency (self , path_lookup : PathLookup , dependency : Dependency ) -> SourceContainer | None : ...
247296
248297
249298class WrappingLoader (DependencyLoader ):
@@ -267,8 +316,7 @@ def register_library(self, path_lookup: PathLookup, *libraries: str) -> list[Dep
267316class BaseNotebookResolver (abc .ABC ):
268317
269318 @abc .abstractmethod
270- def resolve_notebook (self , path_lookup : PathLookup , path : Path ) -> MaybeDependency :
271- """locates a notebook"""
319+ def resolve_notebook (self , path_lookup : PathLookup , path : Path , inherit_context : bool ) -> MaybeDependency : ...
272320
273321 @staticmethod
274322 def _fail (code : str , message : str ) -> MaybeDependency :
@@ -315,8 +363,8 @@ def __init__(
315363 self ._import_resolver = import_resolver
316364 self ._path_lookup = path_lookup
317365
318- def resolve_notebook (self , path_lookup : PathLookup , path : Path ) -> MaybeDependency :
319- return self ._notebook_resolver .resolve_notebook (path_lookup , path )
366+ def resolve_notebook (self , path_lookup : PathLookup , path : Path , inherit_context : bool ) -> MaybeDependency :
367+ return self ._notebook_resolver .resolve_notebook (path_lookup , path , inherit_context )
320368
321369 def resolve_import (self , path_lookup : PathLookup , name : str ) -> MaybeDependency :
322370 return self ._import_resolver .resolve_import (path_lookup , name )
@@ -353,7 +401,8 @@ def _local_file_resolver(self) -> BaseFileResolver | None:
353401 def build_notebook_dependency_graph (self , path : Path , session_state : CurrentSessionState ) -> MaybeGraph :
354402 """Builds a dependency graph starting from a notebook. This method is mainly intended for testing purposes.
355403 In case of problems, the paths in the problems will be relative to the starting path lookup."""
356- maybe = self ._notebook_resolver .resolve_notebook (self ._path_lookup , path )
404+ # the notebook is the root of the graph, so there's no context to inherit
405+ maybe = self ._notebook_resolver .resolve_notebook (self ._path_lookup , path , inherit_context = False )
357406 if not maybe .dependency :
358407 return MaybeGraph (None , self ._make_relative_paths (maybe .problems , path ))
359408 graph = DependencyGraph (maybe .dependency , None , self , self ._path_lookup , session_state )
0 commit comments