|
20 | 20 | from databricks.labs.ucx.assessment.crawlers import runtime_version_tuple |
21 | 21 | from databricks.labs.ucx.hive_metastore.migration_status import MigrationIndex |
22 | 22 | from databricks.labs.ucx.mixins.cached_workspace_path import WorkspaceCache |
23 | | -from databricks.labs.ucx.source_code.base import CurrentSessionState, is_a_notebook, LocatedAdvice |
| 23 | +from databricks.labs.ucx.source_code.base import CurrentSessionState, LocatedAdvice |
24 | 24 | from databricks.labs.ucx.source_code.graph import ( |
25 | 25 | Dependency, |
26 | 26 | DependencyGraph, |
27 | 27 | DependencyProblem, |
28 | 28 | DependencyResolver, |
29 | 29 | SourceContainer, |
30 | 30 | WrappingLoader, |
| 31 | + DependencyGraphWalker, |
31 | 32 | ) |
32 | 33 | from databricks.labs.ucx.source_code.linters.context import LinterContext |
| 34 | +from databricks.labs.ucx.source_code.linters.python_ast import Tree |
33 | 35 | from databricks.labs.ucx.source_code.notebooks.sources import FileLinter |
34 | 36 | from databricks.labs.ucx.source_code.path_lookup import PathLookup |
35 | 37 |
|
@@ -389,51 +391,53 @@ def _lint_job(self, job: jobs.Job) -> list[JobProblem]: |
389 | 391 | return problems |
390 | 392 |
|
391 | 393 | def _lint_task(self, task: jobs.Task, job: jobs.Job, linted_paths: set[Path]) -> Iterable[LocatedAdvice]: |
392 | | - dependency: Dependency = WorkflowTask(self._ws, task, job) |
| 394 | + root_dependency: Dependency = WorkflowTask(self._ws, task, job) |
393 | 395 | # we can load it without further preparation since the WorkflowTask is merely a wrapper |
394 | | - container = dependency.load(self._path_lookup) |
| 396 | + container = root_dependency.load(self._path_lookup) |
395 | 397 | assert isinstance(container, WorkflowTaskContainer) |
396 | 398 | session_state = CurrentSessionState( |
397 | 399 | data_security_mode=container.data_security_mode, |
398 | 400 | named_parameters=container.named_parameters, |
399 | 401 | spark_conf=container.spark_conf, |
400 | 402 | dbr_version=container.runtime_version, |
401 | 403 | ) |
402 | | - graph = DependencyGraph(dependency, None, self._resolver, self._path_lookup, session_state) |
| 404 | + graph = DependencyGraph(root_dependency, None, self._resolver, self._path_lookup, session_state) |
403 | 405 | problems = container.build_dependency_graph(graph) |
404 | 406 | if problems: |
405 | 407 | for problem in problems: |
406 | 408 | source_path = self._UNKNOWN if problem.is_path_missing() else problem.source_path |
407 | 409 | yield LocatedAdvice(problem.as_advisory(), source_path) |
408 | 410 | return |
409 | | - for dependency in graph.root_dependencies: |
410 | | - root = dependency.path # since it's a root |
411 | | - yield from self._lint_one(task, dependency, graph, root, session_state, linted_paths) |
| 411 | + walker = LintingWalker( |
| 412 | + graph, linted_paths, self._path_lookup, task.task_key, session_state, self._migration_index |
| 413 | + ) |
| 414 | + yield from walker |
| 415 | + |
412 | 416 |
|
413 | | - def _lint_one( |
| 417 | +class LintingWalker(DependencyGraphWalker[LocatedAdvice]): |
| 418 | + |
| 419 | + def __init__( |
414 | 420 | self, |
415 | | - task: jobs.Task, |
416 | | - dependency: Dependency, |
417 | 421 | graph: DependencyGraph, |
418 | | - root_path: Path, |
419 | | - session_state: CurrentSessionState, |
420 | 422 | linted_paths: set[Path], |
| 423 | + path_lookup: PathLookup, |
| 424 | + key: str, |
| 425 | + session_state: CurrentSessionState, |
| 426 | + migration_index: MigrationIndex, |
| 427 | + ): |
| 428 | + super().__init__(graph, linted_paths, path_lookup) |
| 429 | + self._key = key |
| 430 | + self._session_state = session_state |
| 431 | + self._migration_index = migration_index |
| 432 | + |
| 433 | + def _log_walk_one(self, dependency: Dependency): |
| 434 | + logger.info(f'Linting {self._key} dependency: {dependency}') |
| 435 | + |
| 436 | + def _process_dependency( |
| 437 | + self, dependency: Dependency, path_lookup: PathLookup, inherited_tree: Tree | None |
421 | 438 | ) -> Iterable[LocatedAdvice]: |
422 | | - if dependency.path in linted_paths: |
423 | | - return |
424 | | - linted_paths.add(dependency.path) |
425 | | - logger.info(f'Linting {task.task_key} dependency: {dependency}') |
426 | | - if dependency.path.is_file() or is_a_notebook(dependency.path): |
427 | | - inherited_tree = graph.root.build_inherited_tree(root_path, dependency.path) |
428 | | - ctx = LinterContext(self._migration_index, session_state) |
429 | | - path_lookup = self._path_lookup.change_directory(dependency.path.parent) |
430 | | - # FileLinter will determine which file/notebook linter to use |
431 | | - linter = FileLinter(ctx, path_lookup, session_state, dependency.path, inherited_tree) |
432 | | - for advice in linter.lint(): |
433 | | - yield LocatedAdvice(advice, dependency.path) |
434 | | - maybe_graph = graph.locate_dependency(dependency.path) |
435 | | - # problems have already been reported while building the graph |
436 | | - if maybe_graph.graph: |
437 | | - child_graph = maybe_graph.graph |
438 | | - for child_dependency in child_graph.local_dependencies: |
439 | | - yield from self._lint_one(task, child_dependency, child_graph, root_path, session_state, linted_paths) |
| 439 | + ctx = LinterContext(self._migration_index, self._session_state) |
| 440 | + # FileLinter determines which file/notebook linter to use |
| 441 | + linter = FileLinter(ctx, path_lookup, self._session_state, dependency.path, inherited_tree) |
| 442 | + for advice in linter.lint(): |
| 443 | + yield LocatedAdvice(advice, dependency.path) |
0 commit comments