diff --git a/dvc/command/add.py b/dvc/command/add.py index 5fcaa95601..813a497ebd 100644 --- a/dvc/command/add.py +++ b/dvc/command/add.py @@ -1,5 +1,5 @@ from dvc.exceptions import DvcException -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase class CmdAdd(CmdBase): diff --git a/dvc/command/common/base.py b/dvc/command/base.py similarity index 100% rename from dvc/command/common/base.py rename to dvc/command/base.py diff --git a/dvc/command/checkout.py b/dvc/command/checkout.py index 32f77c1780..50e519f9a1 100644 --- a/dvc/command/checkout.py +++ b/dvc/command/checkout.py @@ -1,5 +1,5 @@ import os -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase class CmdCheckout(CmdBase): diff --git a/dvc/command/common/__init__.py b/dvc/command/common/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/dvc/command/common/common_error.py b/dvc/command/common/common_error.py deleted file mode 100644 index 3013a73bb8..0000000000 --- a/dvc/command/common/common_error.py +++ /dev/null @@ -1,6 +0,0 @@ -from dvc.exceptions import DvcException - - -class CmdCommonError(DvcException): - def __init__(self, msg): - super(CmdCommonError, self).__init__('{}'.format(msg)) diff --git a/dvc/command/config.py b/dvc/command/config.py index c49d81f681..731ba5c8a9 100644 --- a/dvc/command/config.py +++ b/dvc/command/config.py @@ -1,7 +1,7 @@ import os import configobj -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase from dvc.logger import Logger from dvc.config import Config diff --git a/dvc/command/data_sync.py b/dvc/command/data_sync.py index 3db3d16d4c..f3606630fc 100644 --- a/dvc/command/data_sync.py +++ b/dvc/command/data_sync.py @@ -1,4 +1,4 @@ -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase class CmdDataBase(CmdBase): diff --git a/dvc/command/destroy.py b/dvc/command/destroy.py index 5308239bc5..996fb61a75 100644 --- a/dvc/command/destroy.py +++ b/dvc/command/destroy.py @@ -1,5 +1,6 @@ -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase from dvc.prompt import prompt +from dvc.exceptions import DvcException class CmdDestroy(CmdBase): @@ -10,10 +11,9 @@ def run_cmd(self): u'Are you sure you want to continue?' if not self.args.force and not prompt(msg, False): - err = u'Cannot destroy without a confirmation from the user. ' \ + msg = u'Cannot destroy without a confirmation from the user. ' \ u'Use \'-f\' to force.' - self.project.logger.error(err) - return 1 + raise DvcException(err) self.project.destroy() except Exception as exc: diff --git a/dvc/command/gc.py b/dvc/command/gc.py index 19c4c00369..2bd9fcaffa 100644 --- a/dvc/command/gc.py +++ b/dvc/command/gc.py @@ -1,4 +1,4 @@ -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase class CmdGC(CmdBase): diff --git a/dvc/command/imp.py b/dvc/command/imp.py index abe497838f..8ed3c09501 100644 --- a/dvc/command/imp.py +++ b/dvc/command/imp.py @@ -1,5 +1,5 @@ from dvc.exceptions import DvcException -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase class CmdImport(CmdBase): diff --git a/dvc/command/install.py b/dvc/command/install.py index d91ee6cd55..55d6341de5 100644 --- a/dvc/command/install.py +++ b/dvc/command/install.py @@ -1,5 +1,5 @@ from dvc.logger import Logger -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase class CmdInstall(CmdBase): diff --git a/dvc/command/lock.py b/dvc/command/lock.py index 6e0d5850ad..24a1c42cf5 100644 --- a/dvc/command/lock.py +++ b/dvc/command/lock.py @@ -1,5 +1,5 @@ from dvc.exceptions import DvcException -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase class CmdLockBase(CmdBase): diff --git a/dvc/command/metrics.py b/dvc/command/metrics.py index 8d3e746f71..7014826c65 100644 --- a/dvc/command/metrics.py +++ b/dvc/command/metrics.py @@ -1,4 +1,4 @@ -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase from dvc.exceptions import DvcException diff --git a/dvc/command/move.py b/dvc/command/move.py index bef31165b7..7f2ac6fb79 100644 --- a/dvc/command/move.py +++ b/dvc/command/move.py @@ -1,5 +1,5 @@ from dvc.exceptions import DvcException -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase class CmdMove(CmdBase): diff --git a/dvc/command/pipeline.py b/dvc/command/pipeline.py index 5a7a7237c8..8098d0be4d 100644 --- a/dvc/command/pipeline.py +++ b/dvc/command/pipeline.py @@ -1,7 +1,7 @@ import os from dvc.exceptions import DvcException -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase class CmdPipelineShow(CmdBase): diff --git a/dvc/command/remove.py b/dvc/command/remove.py index e241fe32e5..3fa0260c2e 100644 --- a/dvc/command/remove.py +++ b/dvc/command/remove.py @@ -1,5 +1,5 @@ from dvc.exceptions import DvcException -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase class CmdRemove(CmdBase): diff --git a/dvc/command/repro.py b/dvc/command/repro.py index e6c07658f0..433702ff8a 100644 --- a/dvc/command/repro.py +++ b/dvc/command/repro.py @@ -1,6 +1,6 @@ import os -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase class CmdRepro(CmdBase): diff --git a/dvc/command/root.py b/dvc/command/root.py index 99890da4f4..8d83f5c89e 100644 --- a/dvc/command/root.py +++ b/dvc/command/root.py @@ -1,6 +1,6 @@ import os -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase class CmdRoot(CmdBase): diff --git a/dvc/command/run.py b/dvc/command/run.py index 95d7a636d9..b279e47cee 100644 --- a/dvc/command/run.py +++ b/dvc/command/run.py @@ -1,6 +1,6 @@ import os -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase from dvc.logger import Logger from dvc.exceptions import DvcException diff --git a/dvc/dependency/local.py b/dvc/dependency/local.py index 20705f75d6..278e6d9f5e 100644 --- a/dvc/dependency/local.py +++ b/dvc/dependency/local.py @@ -59,7 +59,7 @@ def save(self): raise self.DoesNotExistError(self.rel_path) if not os.path.isfile(self.path) and not os.path.isdir(self.path): - raise self.NotFileOrDirError(self.rel_path) + raise self.IsNotFileOrDirError(self.rel_path) if (os.path.isfile(self.path) and os.path.getsize(self.path) == 0) or \ (os.path.isdir(self.path) and len(os.listdir(self.path)) == 0): diff --git a/dvc/main.py b/dvc/main.py index 1f708d00f5..1ebc3e6258 100644 --- a/dvc/main.py +++ b/dvc/main.py @@ -1,6 +1,6 @@ from dvc.logger import Logger from dvc.cli import parse_args -from dvc.command.common.base import CmdBase +from dvc.command.base import CmdBase def main(argv=None): diff --git a/dvc/output/local.py b/dvc/output/local.py index 05a8635218..8f7cbbe9bf 100644 --- a/dvc/output/local.py +++ b/dvc/output/local.py @@ -82,7 +82,7 @@ def save(self): raise self.DoesNotExistError(self.rel_path) if not os.path.isfile(self.path) and not os.path.isdir(self.path): - raise self.NotFileOrDirError(self.rel_path) + raise self.IsNotFileOrDirError(self.rel_path) if (os.path.isfile(self.path) and os.path.getsize(self.path) == 0) or \ (os.path.isdir(self.path) and len(os.listdir(self.path)) == 0): diff --git a/tests/test_cli.py b/tests/test_cli.py index c34b6c4645..ee438b4e3e 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -12,6 +12,8 @@ from dvc.command.gc import CmdGC from dvc.command.config import CmdConfig from dvc.command.checkout import CmdCheckout +from dvc.exceptions import DvcException +from dvc.command.base import CmdBase from tests.basic_env import TestDvc @@ -161,3 +163,16 @@ def test(self): t = timeit.default_timer() - start self.assertTrue(t < 0.3) + + +class TestFindRoot(TestDvc): + def test(self): + os.chdir("..") + + class A(object): + quiet = False + verbose = True + + args = A() + with self.assertRaises(DvcException): + CmdBase(args) diff --git a/tests/test_config.py b/tests/test_config.py index d582c354ba..5f9d9ff027 100644 --- a/tests/test_config.py +++ b/tests/test_config.py @@ -1,12 +1,18 @@ import configobj from dvc.main import main +from dvc.command.config import CmdConfig from tests.basic_env import TestDvc class TestConfigCLI(TestDvc): - def _contains(self, section, field, value): - config = configobj.ConfigObj(self.dvc.config.config_file) + def _contains(self, section, field, value, local=False): + if local: + fname = self.dvc.config.config_local_file + else: + fname = self.dvc.config.config_file + + config = configobj.ConfigObj(fname) if section not in config.keys(): return False @@ -22,28 +28,38 @@ def test_root(self): ret = main(['root']) self.assertEqual(ret, 0) - def test(self): + def _do_test(self, local=False): section = 'setsection' field = 'setfield' section_field = '{}.{}'.format(section, field) value = 'setvalue' newvalue = 'setnewvalue' - ret = main(['config', section_field, value]) + base = ['config'] + if local: + base.append('--local') + + ret = main(base + [section_field, value]) self.assertEqual(ret, 0) - self.assertTrue(self._contains(section, field, value)) + self.assertTrue(self._contains(section, field, value, local)) - ret = main(['config', section_field]) + ret = main(base + [section_field]) self.assertEqual(ret, 0) - ret = main(['config', section_field, newvalue]) + ret = main(base + [section_field, newvalue]) self.assertEqual(ret, 0) - self.assertTrue(self._contains(section, field, newvalue)) - self.assertFalse(self._contains(section, field, value)) + self.assertTrue(self._contains(section, field, newvalue, local)) + self.assertFalse(self._contains(section, field, value, local)) - ret = main(['config', section_field, '--unset']) + ret = main(base + [section_field, '--unset']) self.assertEqual(ret, 0) - self.assertFalse(self._contains(section, field, value)) + self.assertFalse(self._contains(section, field, value, local)) + + def test(self): + self._do_test(False) + + def test_local(self): + self._do_test(True) def test_non_existing(self): #FIXME check stdout/err @@ -59,3 +75,23 @@ def test_non_existing(self): ret = main(['config', 'global.non_existing_field', '-u']) self.assertEqual(ret, 1) + + ret = main(['config', 'core.remote', 'myremote']) + self.assertEqual(ret, 0) + + ret = main(['config', 'core.non_existing_field', '-u']) + self.assertEqual(ret, 1) + + def test_failed_write(self): + class A(object): + local = False + name = 'core.remote' + value = 'myremote' + unset = False + + args = A() + cmd = CmdConfig(args) + + cmd.configobj.write = None + ret = cmd.save() + self.assertNotEqual(ret, 0) diff --git a/tests/test_data_cloud.py b/tests/test_data_cloud.py index 0db488247c..011213693f 100644 --- a/tests/test_data_cloud.py +++ b/tests/test_data_cloud.py @@ -381,9 +381,17 @@ def _test_cloud(self, remote=None): sleep() self.main(['status', '-c'] + args) + self.main(['fetch'] + args) + self.assertTrue(os.path.exists(cache)) + self.assertTrue(os.path.isfile(cache)) + self.assertTrue(os.path.isfile(cache_dir)) + self.main(['pull'] + args) self.assertTrue(os.path.exists(cache)) self.assertTrue(os.path.isfile(cache)) + self.assertTrue(os.path.isfile(cache_dir)) + self.assertTrue(os.path.isfile(self.FOO)) + self.assertTrue(os.path.isdir(self.DATA_DIR)) sleep() with open(cache, 'r') as fd: diff --git a/tests/test_logger.py b/tests/test_logger.py index 8959bc4626..5963132454 100644 --- a/tests/test_logger.py +++ b/tests/test_logger.py @@ -1,6 +1,7 @@ import colorama import logging +from dvc.command.base import CmdBase from dvc.config import Config from dvc.logger import Logger @@ -32,3 +33,19 @@ def test_colorize(self): msg = Logger.colorize(name, name) # This is not a tty, so it should not colorize anything self.assertEqual(msg, name) + + +class TestLoggerCLI(TestDvc): + def test(self): + class A(object): + quiet = True + verbose = False + + args = A() + CmdBase._set_loglevel(args) + self.assertEqual(Logger.logger().getEffectiveLevel(), logging.CRITICAL) + + args.quiet = False + args.verbose = True + CmdBase._set_loglevel(args) + self.assertEqual(Logger.logger().getEffectiveLevel(), logging.DEBUG) diff --git a/tests/test_metrics.py b/tests/test_metrics.py index e918002e77..46064ff252 100644 --- a/tests/test_metrics.py +++ b/tests/test_metrics.py @@ -91,6 +91,12 @@ def test(self): ret = main(['repro', '-f', '-m', stage.path]) self.assertNotEqual(ret, 0) + ret = main(['metrics', 'add', 'metrics']) + self.assertEqual(ret, 0) + + ret = main(['repro', '-f', '-m', stage.path]) + self.assertEqual(ret, 0) + def test_dir(self): os.mkdir('metrics_dir') diff --git a/tests/test_pipeline.py b/tests/test_pipeline.py index 5ea44e1cc3..287f174689 100644 --- a/tests/test_pipeline.py +++ b/tests/test_pipeline.py @@ -12,6 +12,10 @@ def test_commands(self): ret = main(['pipeline', 'show', self.file1_stage, '--commands']) self.assertEqual(ret, 0) + def test_outs(self): + ret = main(['pipeline', 'show', self.file1_stage, '--outs']) + self.assertEqual(ret, 0) + def test_not_dvc_file(self): ret = main(['pipeline', 'show', self.file1]) self.assertNotEqual(ret, 0) diff --git a/tests/test_remote.py b/tests/test_remote.py index cdc74e5c70..d8c5c92199 100644 --- a/tests/test_remote.py +++ b/tests/test_remote.py @@ -1,4 +1,5 @@ from dvc.main import main +from dvc.command.remote import CmdRemoteAdd from tests.basic_env import TestDvc @@ -19,3 +20,17 @@ def test(self): self.assertEqual(main(['remote', 'modify', remotes[0], 'option', 'value']), 0) self.assertEqual(main(['remote', 'list']), 0) + + def test_failed_write(self): + class A(object): + local = False + name = 'myremote' + url = 's3://remote' + unset = False + + args = A() + cmd = CmdRemoteAdd(args) + + cmd.configobj.write = None + ret = cmd.run() + self.assertNotEqual(ret, 0) diff --git a/tests/test_repro.py b/tests/test_repro.py index 8fa6d84d32..d7112c82b8 100644 --- a/tests/test_repro.py +++ b/tests/test_repro.py @@ -40,6 +40,14 @@ def setUp(self): cmd='python {} {} {}'.format(self.CODE, self.FOO, self.file1)) +class TestReproFail(TestRepro): + def test(self): + os.unlink(self.CODE) + + ret = main(['repro', self.file1_stage]) + self.assertNotEqual(ret, 0) + + class TestReproDepUnderDir(TestDvc): def test(self): self.dir_stage = self.dvc.add(self.DATA_DIR)