internal: hoist resolver/top-level metrics/plots/params data into file level

This commit is contained in:
Saugat Pachhai (सौगात)
2023-01-03 17:46:06 +05:45
committed by skshetry
parent f386f7c082
commit a24c389674
6 changed files with 73 additions and 42 deletions
+49 -4
View File
@@ -1,7 +1,18 @@
import contextlib
import logging
import os
from typing import TYPE_CHECKING, Any, Callable, Tuple, TypeVar, Union
from typing import (
TYPE_CHECKING,
Any,
Callable,
Dict,
List,
Tuple,
TypeVar,
Union,
)
from funcy import cached_property
from dvc.exceptions import DvcException
from dvc.parsing.versions import LOCKFILE_VERSION, SCHEMA_KWD
@@ -180,6 +191,10 @@ class SingleStageFile(FileMixin):
from dvc.schema import COMPILED_SINGLE_STAGE_SCHEMA as SCHEMA
from dvc.stage.loader import SingleStageLoader as LOADER
metrics: List[str] = []
plots: Dict[str, Any] = {}
params: List[str] = []
@property
def stage(self):
data, raw = self._load()
@@ -223,6 +238,11 @@ class PipelineFile(FileMixin):
def _lockfile(self):
return Lockfile(self.repo, os.path.splitext(self.path)[0] + ".lock")
def _reset(self):
self.__dict__.pop("contents", None)
self.__dict__.pop("lockfile_contents", None)
self.__dict__.pop("resolver", None)
def dump(
self, stage, update_pipeline=True, update_lock=True, **kwargs
): # pylint: disable=arguments-differ
@@ -278,11 +298,36 @@ class PipelineFile(FileMixin):
"PipelineFile has multiple stages. Please specify it's name."
)
@cached_property
def contents(self):
return self._load()[0]
@cached_property
def lockfile_contents(self):
return self._lockfile.load()
@cached_property
def resolver(self):
from .parsing import DataResolver
wdir = self.repo.fs.path.parent(self.path)
return DataResolver(self.repo, wdir, self.contents)
@property
def stages(self):
data, _ = self._load()
lockfile_data = self._lockfile.load()
return self.LOADER(self, data, lockfile_data)
return self.LOADER(self, self.contents, self.lockfile_contents)
@property
def metrics(self):
return self.contents.get("metrics", [])
@property
def plots(self):
return self.contents.get("plots", {})
@property
def params(self):
return self.contents.get("params", [])
def remove(self, force=False):
if not force:
+5 -17
View File
@@ -517,7 +517,6 @@ class StageLoad:
path = self._get_filepath(path)
dvcfile = Dvcfile(self.repo, path)
# `dvcfile.stages` is not cached
stages = dvcfile.stages # type: ignore
if isinstance(stages, SingleStageLoader):
@@ -526,13 +525,7 @@ class StageLoad:
assert isinstance(stages, StageLoader)
keys = self._get_keys(stages)
stages_ = [stages[key] for key in keys]
return (
stages_,
stages.metrics_data,
stages.plots_data,
stages.params_data,
)
return stages_, dvcfile
def _collect_all_from_repo(
self, onerror: Callable[[str, Exception], None] = None
@@ -583,12 +576,7 @@ class StageLoad:
for file in filter(dvcfile_filter, files):
file_path = self.fs.path.join(root, file)
try:
(
new_stages,
new_metrics,
new_plots,
new_params,
) = self._load_file(file_path)
new_stages, dvcfile = self._load_file(file_path)
except DvcException as exc:
if onerror:
onerror(relpath(file_path), exc)
@@ -596,11 +584,11 @@ class StageLoad:
raise
stages.extend(new_stages)
if new_metrics:
if new_metrics := dvcfile.metrics:
metrics[file_path] = new_metrics
if new_plots:
if new_plots := dvcfile.plots:
plots[file_path] = new_plots
if new_params:
if new_params := dvcfile.params:
params[file_path] = new_params
outs.update(
+1
View File
@@ -775,6 +775,7 @@ class PipelineStage(Stage):
return f"{super().addressing}:{self.name}"
def reload(self):
self.dvcfile._reset() # pylint: disable=protected-access
return self.dvcfile.stages[self.name]
def _status_stage(self, ret):
+8 -13
View File
@@ -6,7 +6,7 @@ from itertools import chain
from funcy import cached_property, get_in, lcat, once, project
from dvc import dependency, output
from dvc.parsing import FOREACH_KWD, JOIN, DataResolver, EntryNotFound
from dvc.parsing import FOREACH_KWD, JOIN, EntryNotFound
from dvc.parsing.versions import LOCKFILE_VERSION
from dvc_data.hashfile.hash_info import HashInfo
from dvc_data.hashfile.meta import Meta
@@ -20,13 +20,16 @@ logger = logging.getLogger(__name__)
class StageLoader(Mapping):
def __init__(self, dvcfile, data, lockfile_data=None):
def __init__(
self,
dvcfile,
data,
lockfile_data=None,
):
self.dvcfile = dvcfile
self.resolver = self.dvcfile.resolver
self.data = data or {}
self.stages_data = self.data.get("stages", {})
self.metrics_data = self.data.get("metrics", [])
self.params_data = self.data.get("params", [])
self.plots_data = self.data.get("plots", {})
self.repo = self.dvcfile.repo
lockfile_data = lockfile_data or {}
@@ -36,11 +39,6 @@ class StageLoader(Mapping):
else:
self._lockfile_data = lockfile_data.get("stages", {})
@cached_property
def resolver(self):
wdir = self.repo.fs.path.parent(self.dvcfile.path)
return DataResolver(self.repo, wdir, self.data)
@cached_property
def lockfile_data(self):
if not self._lockfile_data:
@@ -174,9 +172,6 @@ class SingleStageLoader(Mapping):
self.dvcfile = dvcfile
self.stage_data = stage_data or {}
self.stage_text = stage_text
self.metrics_data = []
self.params_data = []
self.plots_data = {}
def __getitem__(self, item):
if item:
+2
View File
@@ -317,6 +317,8 @@ def test_stage_remove_pipeline_stage(tmp_dir, dvc, run_copy):
with dvc.lock:
stage.remove()
dvc_file._reset()
assert stage.name not in dvc_file.stages
assert "copy-bar-foobar" in dvc_file.stages
@@ -247,11 +247,11 @@ def test_load_stage_wdir_and_path_correctly(dvc, stage_data, lock_data):
def test_load_stage_mapping(dvc, stage_data, lock_data):
dvcfile = Dvcfile(dvc, PIPELINE_FILE)
loader = StageLoader(
dvcfile, {"stages": {"stage": stage_data}}, {"stage": lock_data}
)
assert len(loader) == 1
assert "stage" in loader
assert "stage1" not in loader
assert loader.keys() == {"stage"}
assert isinstance(loader["stage"], PipelineStage)
dvcfile.contents = {"stages": {"stage": stage_data}}
dvcfile.lockfile_contents = {"stage": lock_data}
assert len(dvcfile.stages) == 1
assert "stage" in dvcfile.stages
assert "stage1" not in dvcfile.stages
assert dvcfile.stages.keys() == {"stage"}
assert isinstance(dvcfile.stages["stage"], PipelineStage)