|
5 | 5 | from pathlib import Path |
6 | 6 | from typing import Any, Dict, List, Optional, Set, Union |
7 | 7 |
|
| 8 | +from dvc.exceptions import DvcException |
8 | 9 | from dvc_studio_client.post_live_metrics import post_live_metrics |
9 | 10 | from funcy import set_in |
10 | | -from pathspec import PathSpec |
11 | 11 | from ruamel.yaml.representer import RepresenterError |
12 | 12 |
|
13 | 13 | from . import env |
14 | 14 | from .dvc import ( |
| 15 | + ensure_dir_is_tracked, |
15 | 16 | find_overlapping_stage, |
16 | 17 | get_dvc_repo, |
17 | 18 | get_random_exp_name, |
|
31 | 32 | from .studio import get_dvc_studio_config, get_studio_updates |
32 | 33 | from .utils import ( |
33 | 34 | StrPath, |
| 35 | + catch_and_warn, |
34 | 36 | clean_and_copy_into, |
35 | 37 | env2bool, |
36 | 38 | inside_notebook, |
@@ -124,6 +126,7 @@ def _init_cleanup(self): |
124 | 126 | if self.dvc_file and os.path.exists(self.dvc_file): |
125 | 127 | os.remove(self.dvc_file) |
126 | 128 |
|
| 129 | + @catch_and_warn(DvcException, logger) |
127 | 130 | def _init_dvc(self): |
128 | 131 | from dvc.scm import NoSCM |
129 | 132 |
|
@@ -453,35 +456,31 @@ def log_artifact( |
453 | 456 | name, |
454 | 457 | ) |
455 | 458 |
|
| 459 | + @catch_and_warn(DvcException, logger) |
456 | 460 | def cache(self, path): |
457 | | - try: |
458 | | - if self._inside_dvc_exp: |
459 | | - existing_stage = find_overlapping_stage(self._dvc_repo, path) |
460 | | - |
461 | | - if existing_stage: |
462 | | - if existing_stage.cmd: |
463 | | - logger.info( |
464 | | - f"Skipping `dvc add {path}` because it is already being" |
465 | | - " tracked automatically as an output of `dvc exp run`." |
466 | | - ) |
467 | | - return # skip caching |
468 | | - logger.warning( |
469 | | - f"To track '{path}' automatically during `dvc exp run`:" |
470 | | - f"\n1. Run `dvc remove {existing_stage.addressing}` " |
471 | | - "to stop tracking it outside the pipeline." |
472 | | - "\n2. Add it as an output of the pipeline stage." |
473 | | - ) |
474 | | - else: |
475 | | - logger.warning( |
476 | | - f"To track '{path}' automatically during `dvc exp run`, " |
477 | | - "add it as an output of the pipeline stage." |
478 | | - ) |
| 461 | + if self._inside_dvc_exp: |
| 462 | + existing_stage = find_overlapping_stage(self._dvc_repo, path) |
479 | 463 |
|
480 | | - stage = self._dvc_repo.add(str(path)) |
| 464 | + if existing_stage: |
| 465 | + if existing_stage.cmd: |
| 466 | + logger.info( |
| 467 | + f"Skipping `dvc add {path}` because it is already being" |
| 468 | + " tracked automatically as an output of `dvc exp run`." |
| 469 | + ) |
| 470 | + return # skip caching |
| 471 | + logger.warning( |
| 472 | + f"To track '{path}' automatically during `dvc exp run`:" |
| 473 | + f"\n1. Run `dvc remove {existing_stage.addressing}` " |
| 474 | + "to stop tracking it outside the pipeline." |
| 475 | + "\n2. Add it as an output of the pipeline stage." |
| 476 | + ) |
| 477 | + else: |
| 478 | + logger.warning( |
| 479 | + f"To track '{path}' automatically during `dvc exp run`, " |
| 480 | + "add it as an output of the pipeline stage." |
| 481 | + ) |
481 | 482 |
|
482 | | - except Exception as e: # noqa: BLE001 |
483 | | - logger.warning(f"Failed to dvc add {path}: {e}") |
484 | | - return |
| 483 | + stage = self._dvc_repo.add(str(path)) |
485 | 484 |
|
486 | 485 | dvc_file = stage[0].addressing |
487 | 486 |
|
@@ -539,7 +538,10 @@ def end(self): |
539 | 538 | if self._dvcyaml: |
540 | 539 | self.make_dvcyaml() |
541 | 540 |
|
542 | | - self._ensure_paths_are_tracked_in_dvc_exp() |
| 541 | + if self._inside_dvc_exp and self._dvc_repo: |
| 542 | + catch_and_warn(DvcException, logger)(ensure_dir_is_tracked)( |
| 543 | + self.dir, self._dvc_repo |
| 544 | + ) |
543 | 545 |
|
544 | 546 | self.save_dvc_exp() |
545 | 547 |
|
@@ -582,35 +584,12 @@ def __exit__(self, exc_type, exc_val, exc_tb): |
582 | 584 | self._inside_with = False |
583 | 585 | self.end() |
584 | 586 |
|
585 | | - def _ensure_paths_are_tracked_in_dvc_exp(self): |
586 | | - if self._inside_dvc_exp and self._dvc_repo: |
587 | | - dir_spec = PathSpec.from_lines("gitwildmatch", [self.dir]) |
588 | | - outs_spec = PathSpec.from_lines( |
589 | | - "gitwildmatch", [str(o) for o in self._dvc_repo.index.outs] |
590 | | - ) |
591 | | - try: |
592 | | - paths_to_track = [ |
593 | | - f |
594 | | - for f in self._dvc_repo.scm.untracked_files() |
595 | | - if (dir_spec.match_file(f) and not outs_spec.match_file(f)) |
596 | | - ] |
597 | | - if paths_to_track: |
598 | | - self._dvc_repo.scm.add(paths_to_track) |
599 | | - except Exception as e: # noqa: BLE001 |
600 | | - logger.warning(f"Failed to git add paths:\n{e}") |
601 | | - |
| 587 | + @catch_and_warn(DvcException, logger, mark_dvclive_only_ended) |
602 | 588 | def save_dvc_exp(self): |
603 | 589 | if self._save_dvc_exp: |
604 | | - from dvc.exceptions import DvcException |
605 | | - |
606 | | - try: |
607 | | - self._experiment_rev = self._dvc_repo.experiments.save( |
608 | | - name=self._exp_name, |
609 | | - include_untracked=self._include_untracked, |
610 | | - force=True, |
611 | | - message=self._exp_message, |
612 | | - ) |
613 | | - except DvcException as e: |
614 | | - logger.warning(f"Failed to save experiment:\n{e}") |
615 | | - finally: |
616 | | - mark_dvclive_only_ended() |
| 590 | + self._experiment_rev = self._dvc_repo.experiments.save( |
| 591 | + name=self._exp_name, |
| 592 | + include_untracked=self._include_untracked, |
| 593 | + force=True, |
| 594 | + message=self._exp_message, |
| 595 | + ) |
0 commit comments