diff --git a/dvc/cli.py b/dvc/cli.py index 4da5a604b..11e8e84b4 100644 --- a/dvc/cli.py +++ b/dvc/cli.py @@ -336,7 +336,6 @@ def parse_args(argv=None): repro_parser.add_argument( 'targets', nargs='*', - default=['Dvcfile'], help='DVC file to reproduce.') repro_parser.add_argument( '-f', @@ -763,4 +762,14 @@ def parse_args(argv=None): args = parser.parse_args(argv) + if args.cmd == 'repro' and len(args.targets) == 0: + path = os.path.join(args.cwd, 'Dvcfile') + if not os.path.exists(path): + msg = "error: default target '{}' does not exist.\n" + sys.stderr.write(msg.format(path)) + sys.stderr.flush() + repro_parser.print_help() + sys.exit(2) + args.targets = ['Dvcfile'] + return args diff --git a/dvc/command/pipeline.py b/dvc/command/pipeline.py index 8098d0be4..299da9fe1 100644 --- a/dvc/command/pipeline.py +++ b/dvc/command/pipeline.py @@ -7,13 +7,12 @@ from dvc.command.base import CmdBase class CmdPipelineShow(CmdBase): def _show(self, target, commands, outs): import networkx - from dvc.project import NotDvcFileError + from dvc.stage import Stage + stage = Stage.load(self.project, target) G = self.project.graph()[0] stages = networkx.get_node_attributes(G, 'stage') - node = os.path.relpath(os.path.abspath(target), self.project.root_dir) - if node not in stages: - raise NotDvcFileError(node) + node = os.path.relpath(stage.path, self.project.root_dir) for n in networkx.dfs_postorder_nodes(G, node): if commands: diff --git a/dvc/command/repro.py b/dvc/command/repro.py index 3d8daa8fd..7a8ad0955 100644 --- a/dvc/command/repro.py +++ b/dvc/command/repro.py @@ -1,12 +1,11 @@ import os from dvc.command.base import CmdBase +from dvc.exceptions import DvcException class CmdRepro(CmdBase): def run(self): - from dvc.project import ReproductionError - recursive = not self.args.single_item saved_dir = os.path.realpath(os.curdir) if self.args.cwd: diff --git a/dvc/stage.py b/dvc/stage.py index 31d2b2d47..1708e1797 100644 --- a/dvc/stage.py +++ b/dvc/stage.py @@ -24,6 +24,18 @@ class StageFileFormatError(DvcException): super(StageFileFormatError, self).__init__('Stage file format error') +class StageFileDoesNotExistError(DvcException): + def __init__(self, fname): + msg = "'{}' does not exist.".format(fname) + super(StageFileDoesNotExistError, self).__init__(msg) + + +class StageFileIsNotDvcFileError(DvcException): + def __init__(self, fname): + msg = "'{}' is not a dvc file".format(fname) + super(StageFileIsNotDvcFileError, self).__init__(msg) + + class MissingDataSource(DvcException): def __init__(self, missing_files): assert len(missing_files) > 0 @@ -266,18 +278,18 @@ class Stage(object): @staticmethod def _check_dvc_file(fname): sname = fname + Stage.STAGE_FILE_SUFFIX - if Stage.is_stage_file(sname): - self.info("Do you mean '{}'?".format(sname)) + if Stage.is_stage_file(sname): + Logger.info("Do you mean '{}'?".format(sname)) @staticmethod def load(project, fname): if not os.path.exists(fname): Stage._check_dvc_file(fname) - raise DvcException("'{}' does not exist.".format(fname)) + raise StageFileDoesNotExistError(fname) - if not self.is_stage_file(fname): + if not Stage.is_stage_file(fname): Stage._check_dvc_file(fname) - raise DvcException("'{}' is not a DVC file".format(fname)) + raise StageFileIsNotDvcFileError(fname) with open(fname, 'r') as fd: return Stage.loadd(project, yaml.safe_load(fd), fname) diff --git a/tests/test_remove.py b/tests/test_remove.py index 4e2ad1ef5..cd21f82b9 100644 --- a/tests/test_remove.py +++ b/tests/test_remove.py @@ -1,8 +1,7 @@ import os from dvc.main import main -from dvc.stage import Stage -from dvc.project import NotDvcFileError +from dvc.stage import Stage, StageFileDoesNotExistError from dvc.command.remove import CmdRemove from tests.basic_env import TestDvc @@ -26,7 +25,7 @@ class TestRemove(TestDvc): class TestRemoveNonExistentFile(TestDvc): def test(self): - with self.assertRaises(NotDvcFileError) as cx: + with self.assertRaises(StageFileDoesNotExistError) as cx: self.dvc.remove('non_existent_dvc_file') diff --git a/tests/test_repro.py b/tests/test_repro.py index 76ed53c6d..95627272c 100644 --- a/tests/test_repro.py +++ b/tests/test_repro.py @@ -14,10 +14,10 @@ from google.cloud import storage as gc from dvc.main import main from dvc.command.repro import CmdRepro -from dvc.project import Project, ReproductionError, NotDvcFileError +from dvc.project import Project, ReproductionError from dvc.utils import file_md5 from dvc.remote.local import RemoteLOCAL -from dvc.stage import Stage +from dvc.stage import Stage, StageFileDoesNotExistError from tests.basic_env import TestDvc from tests.test_data_cloud import _should_test_aws, TEST_AWS_REPO_BUCKET @@ -134,7 +134,8 @@ class TestReproDry(TestReproChangedData): self.assertTrue(len(stages), 2) self.assertFalse(filecmp.cmp(self.file1, self.BAR, shallow=False)) - ret = main(['repro', '--dry']) + ret = main(['repro', '--dry', self.file1_stage]) + self.assertEqual(ret, 0) self.assertFalse(filecmp.cmp(self.file1, self.BAR, shallow=False)) @@ -180,7 +181,7 @@ class TestReproLocked(TestReproChangedData): self.assertEqual(len(stages), 3) def test_non_existing(self): - with self.assertRaises(NotDvcFileError): + with self.assertRaises(StageFileDoesNotExistError): self.dvc.lock_stage('non-existing-stage') ret = main(['lock', 'non-existing-stage'])