Repository: iterative/dvc

Issue:
dvc exp run: Checks out deps and outs of all stages even if not required by stage to run
# Bug Report

<!--
## Issue name

Issue names must follow the pattern `command: description` where the command is the dvc command that you are trying to run. The description should describe the consequence of the bug. 

Example: `repro: doesn't detect input changes`
-->

## Description

<!--
A clear and concise description of what the bug is.
-->

When executing `dvc exp run` (with or without `--temp`, also when specifying `--single-item`), it checks out all cached deps (and outs?) of stages listed in the `dvc.yaml` file of the stage specified as target, and also all stages in other `dvc.yaml` files of other pipelines in the same DVC project.

### Reproduce

<!--
Step list of how to reproduce the bug
-->

<!--
Example:

1. dvc init
2. Copy dataset.zip to the directory
3. dvc add dataset.zip
4. dvc run -d dataset.zip -o model ./train.sh
5. modify dataset.zip
6. dvc repro
-->

### Expected

<!--
A clear and concise description of what you expect to happen.
-->

Command `dvc run exp target` should only checkout the data files specified as `deps` of the `target` to run, plus maybe all previous stages in the pipeline that produce these if necessary and when `--single-item` is not specified. Especially when using the `--temp` option (i.e., `--queue` + `--run-all`), this results in a long wait for `dvc` to check out many data files from unrelated pipelines / stages.

### Environment information

<!--
This is required to ensure that we can reproduce the bug.
-->

**Output of `dvc version`:**

```console
$ dvc version
DVC version: 2.0.0a0+273b02
---------------------------------
Platform: Python 3.7.9 on Linux-3.10.0-1127.8.2.el7.x86_64-x86_64-with-centos-7.8.2003-Core
Supports: http, https, s3
```

**Additional Information (if any):**

<!--
If applicable, please also provide a `--verbose` output of the command, eg: `dvc add --verbose`.
-->


Discussion:

Resolving patch:
diff --git a/dvc/repo/experiments/executor/base.py b/dvc/repo/experiments/executor/base.py
--- a/dvc/repo/experiments/executor/base.py
+++ b/dvc/repo/experiments/executor/base.py
@@ -248,6 +248,10 @@ def filter_pipeline(stages):
 
         with cls._repro_dvc(dvc_dir, rel_cwd) as dvc:
             args, kwargs = cls._repro_args(dvc)
+            if args:
+                targets: Optional[Union[list, str]] = args[0]
+            else:
+                targets = kwargs.get("targets")
 
             repro_force = kwargs.get("force", False)
             logger.trace(  # type: ignore[attr-defined]
@@ -265,7 +269,14 @@ def filter_pipeline(stages):
             #   be removed/does not yet exist) so that our executor workspace
             #   is not polluted with the (persistent) out from an unrelated
             #   experiment run
-            dvc_checkout(dvc, force=True, quiet=True, allow_missing=True)
+            dvc_checkout(
+                dvc,
+                targets=targets,
+                with_deps=targets is not None,
+                force=True,
+                quiet=True,
+                allow_missing=True,
+            )
 
             checkpoint_func = partial(
                 cls.checkpoint_callback, dvc.scm, name, repro_force


Test patch:
diff --git a/tests/func/experiments/test_experiments.py b/tests/func/experiments/test_experiments.py
--- a/tests/func/experiments/test_experiments.py
+++ b/tests/func/experiments/test_experiments.py
@@ -612,3 +612,24 @@ def test_remove(tmp_dir, scm, dvc, exp_stage):
     removed = dvc.experiments.remove(queue=True)
     assert removed == 1
     assert len(dvc.experiments.stash) == 0
+
+
+def test_checkout_targets_deps(tmp_dir, scm, dvc, exp_stage):
+    from dvc.utils.fs import remove
+
+    tmp_dir.dvc_gen({"foo": "foo", "bar": "bar"}, commit="add files")
+    stage = dvc.stage.add(
+        cmd="python copy.py params.yaml metrics.yaml",
+        metrics_no_cache=["metrics.yaml"],
+        params=["foo"],
+        name="copy-file",
+        deps=["copy.py", "foo"],
+        force=True,
+    )
+    remove("foo")
+    remove("bar")
+
+    dvc.experiments.run(stage.addressing, params=["foo=2"])
+    assert (tmp_dir / "foo").exists()
+    assert (tmp_dir / "foo").read_text() == "foo"
+    assert not (tmp_dir / "bar").exists()