Repository: iterative/dvc

Issue:
run: params are not checked before running the command
```
$ dvc run -n train1 -d users.csv -p tr_conf.yaml:epochs1,log_file,dropout -M e1/summary.json -m e1/logs.csv -o e1/logs python train.py
.... training is happening
.... 27 hours latter:
60000/60000 [==============================] - 6s 94us/sample - loss: 0.0588 - accuracy: 0.9806 - val_loss: 0.0707 - val_accuracy: 0.9821
ERROR: failed to run command - Parameters 'epochs1' are missing from 'tr_conf.yaml'.
```

Discussion:

Patch:
diff --git a/dvc/stage/__init__.py b/dvc/stage/__init__.py
index 6c78c65de..e1c629abd 100644
--- a/dvc/stage/__init__.py
+++ b/dvc/stage/__init__.py
@@ -21,7 +21,6 @@ from .exceptions import (
     StagePathNotDirectoryError,
     StageCommitError,
     StageUpdateError,
-    MissingDep,
     MissingDataSource,
 )
 from . import params
@@ -374,8 +373,7 @@ class Stage(params.StageParams):
 
         # NOTE: need to save checksums for deps in order to compare them
         # with what is written in the old stage.
-        for dep in self.deps:
-            dep.save()
+        self._save_deps()
 
         old_d = old.dumpd()
         new_d = self.dumpd()
@@ -482,10 +480,13 @@ class Stage(params.StageParams):
         logger.debug("Computed {} md5: '{}'".format(self, m))
         return m
 
-    def save(self):
+    def _save_deps(self):
         for dep in self.deps:
             dep.save()
 
+    def save(self):
+        self._save_deps()
+
         for out in self.outs:
             out.save()
 
@@ -526,12 +527,6 @@ class Stage(params.StageParams):
         for out in self.outs:
             out.commit()
 
-    def _check_missing_deps(self):
-        missing = [dep for dep in self.deps if not dep.exists]
-
-        if any(missing):
-            raise MissingDep(missing)
-
     @staticmethod
     def _warn_if_fish(executable):  # pragma: no cover
         if (
@@ -570,8 +565,6 @@ class Stage(params.StageParams):
 
     @unlocked_repo
     def _run(self):
-        self._check_missing_deps()
-
         kwargs = {"cwd": self.wdir, "env": fix_env(None), "close_fds": True}
 
         if os.name == "nt":
@@ -667,6 +660,7 @@ class Stage(params.StageParams):
                     logger.info("Stage is cached, skipping.")
                     self.checkout()
                 else:
+                    self._save_deps()
                     logger.info("Running command:\n\t{}".format(self.cmd))
                     self._run()
 
diff --git a/dvc/stage/exceptions.py b/dvc/stage/exceptions.py
index 3049826c4..4d10bc40f 100644
--- a/dvc/stage/exceptions.py
+++ b/dvc/stage/exceptions.py
@@ -73,15 +73,6 @@ class StageUpdateError(DvcException):
         )
 
 
-class MissingDep(DvcException):
-    def __init__(self, deps):
-        assert len(deps) > 0
-
-        dep = "dependencies" if len(deps) > 1 else "dependency"
-        msg = "missing '{}': {}".format(dep, ", ".join(map(str, deps)))
-        super().__init__(msg)
-
-
 class MissingDataSource(DvcException):
     def __init__(self, missing_files):
         assert len(missing_files) > 0


Test patch:
diff --git a/tests/func/test_run_single_stage.py b/tests/func/test_run_single_stage.py
index a5e9a34d7..049aa5ed0 100644
--- a/tests/func/test_run_single_stage.py
+++ b/tests/func/test_run_single_stage.py
@@ -26,7 +26,6 @@ from dvc.stage.exceptions import (
     StagePathOutsideError,
     StagePathNotFoundError,
     StagePathNotDirectoryError,
-    MissingDep,
 )
 from dvc.system import System
 from dvc.utils import file_md5
@@ -79,7 +78,9 @@ class TestRunEmpty(TestDvc):
 
 class TestRunMissingDep(TestDvc):
     def test(self):
-        with self.assertRaises(MissingDep):
+        from dvc.dependency.base import DependencyDoesNotExistError
+
+        with self.assertRaises(DependencyDoesNotExistError):
             self.dvc.run(
                 cmd="",
                 deps=["non-existing-dep"],