diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 000000000..1408127c3 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,7 @@ +[run] +omit = + *__main__.py + +[report] +exclude_lines = + if __name__ == .__main__.: diff --git a/dvc.py b/dvc.py index 78bdb4e24..0040e8419 100755 --- a/dvc.py +++ b/dvc.py @@ -1,4 +1,6 @@ +import sys + from dvc.main import main if __name__ == "__main__": - main() + main(sys.argv[1:]) diff --git a/dvc/__main__.py b/dvc/__main__.py index 74fb03c3d..964065a73 100644 --- a/dvc/__main__.py +++ b/dvc/__main__.py @@ -1,4 +1,6 @@ +import sys + from dvc.main import main if __name__ == '__main__': - main() + main(sys.argv[1:]) diff --git a/dvc/cli.py b/dvc/cli.py index cea296125..b771fe25e 100644 --- a/dvc/cli.py +++ b/dvc/cli.py @@ -39,12 +39,6 @@ def parse_args(argv=None): action='store_true', default=False, help='Be verbose.') - parent_parser.add_argument( - '-G', - '--no-git-actions', - action='store_true', - default=False, - help='Skip all git actions including reproducibility check and commits.') parent_parser.add_argument( '-b', @@ -221,20 +215,6 @@ def parse_args(argv=None): 'gc', parents=[parent_parser], help='Collect garbage') - gc_parser.add_argument('-l', - '--keep-in-cloud', - action='store_true', - default=False, - help='Do not remove data from cloud.') - gc_parser.add_argument('-r', - '--recursive', - action='store_true', - help='Remove directory recursively.') - gc_parser.add_argument('-c', - '--keep-in-cache', - action='store_false', - default=False, - help='Do not remove data from cache.') gc_parser.set_defaults(func=CmdGC) # Cloud @@ -339,12 +319,13 @@ def parse_args(argv=None): parents=[parent_parser], help='Show graphs') show_subparsers = show_parser.add_subparsers( - dest='cmd', - help='Use `dvc show CMD` --help for command-specific help') + dest='cmd', + help='Use `dvc show CMD` --help for command-specific help') + pipeline_parser = show_subparsers.add_parser( - 'pipeline', - parents=[parent_parser], - help='Show pipeline image') + 'pipeline', + parents=[parent_parser], + help='Show pipeline image') pipeline_parser.add_argument( 'target', nargs='*', @@ -431,7 +412,4 @@ def parse_args(argv=None): help='Compute actual md5') fsck_parser.set_defaults(func=CmdFsck) - if isinstance(argv, str): - argv = argv.split() - return parser.parse_args(argv) diff --git a/dvc/command/common/base.py b/dvc/command/common/base.py index 805474e4b..7d9316b2c 100644 --- a/dvc/command/common/base.py +++ b/dvc/command/common/base.py @@ -21,7 +21,7 @@ class CmdBase(object): return root root = os.path.dirname(root) msg = "Not a dvc repository (or any parent up to mount point {})" - Logger.error(msg.format(root)) + self.project.logger.error(msg.format(root)) def run_cmd(self): with self.project.lock: diff --git a/dvc/main.py b/dvc/main.py index 280055aba..a97dfdde8 100644 --- a/dvc/main.py +++ b/dvc/main.py @@ -1,5 +1,5 @@ from dvc.cli import parse_args -def main(): - args = parse_args() +def main(argv=None): + args = parse_args(argv) return args.func(args).run_cmd() diff --git a/tests/test_cli.py b/tests/test_cli.py new file mode 100644 index 000000000..4481b605c --- /dev/null +++ b/tests/test_cli.py @@ -0,0 +1,236 @@ +import os + +from dvc.cli import parse_args +from dvc.command.init import CmdInit +from dvc.command.run import CmdRun +from dvc.command.data_sync import CmdDataPull, CmdDataPush, CmdDataStatus +from dvc.command.repro import CmdRepro +from dvc.command.add import CmdAdd +from dvc.command.remove import CmdRemove +from dvc.command.lock import CmdLock +from dvc.command.gc import CmdGC +from dvc.command.config import CmdConfig +from dvc.command.show_pipeline import CmdShowPipeline +from dvc.command.show_workflow import CmdShowWorkflow +from dvc.command.checkout import CmdCheckout +from dvc.command.find import CmdFind +from dvc.command.fsck import CmdFsck + +from tests.basic_env import TestDvc + + +class TestArgParse(TestDvc): + def test(self): + args = parse_args(['init']) + self.assertIsInstance(args.func(args), CmdInit) + + +class TestRun(TestDvc): + def test(self): + dep1 = 'dep1' + dep2 = 'dep2' + + out1 = 'out1' + out2 = 'out2' + + out_no_cache1 = 'out_no_cache1' + out_no_cache2 = 'out_no_cache2' + + fname = 'dvc.dvc' + cwd = os.curdir + cmd = 'cmd' + arg1 = 'arg1' + arg2 = 'arg2' + + args = parse_args(['run', + '-d', dep1, + '--deps', dep2, + '-o', out1, + '--outs', out2, + '-O', out_no_cache1, + '--outs-no-cache', out_no_cache2, + '-l', '--lock', + '-f', fname, + '--file', fname, + '-c', cwd, + cmd, arg1, arg2]) + + self.assertIsInstance(args.func(args), CmdRun) + self.assertEqual(args.deps, [dep1, dep2]) + self.assertEqual(args.outs, [out1, out2]) + self.assertEqual(args.outs_no_cache, [out_no_cache1, out_no_cache2]) + self.assertEqual(args.file, fname) + self.assertEqual(args.cwd, cwd) + self.assertEqual(args.command, [cmd, arg1, arg2]) + + +class TestPull(TestDvc): + def test(self): + args = parse_args(['pull']) + self.assertIsInstance(args.func(args), CmdDataPull) + + +class TestPush(TestDvc): + def test(self): + args = parse_args(['push']) + self.assertIsInstance(args.func(args), CmdDataPush) + + +class TestStatus(TestDvc): + def test(self): + args = parse_args(['status']) + self.assertIsInstance(args.func(args), CmdDataStatus) + + +class TestRepro(TestDvc): + def test(self): + target1 = '1' + target2 = '2' + + args = parse_args(['repro', + target1, + target2, + '-f', '--force', + '-s', '--single-item']) + + self.assertIsInstance(args.func(args), CmdRepro) + self.assertEqual(args.targets, [target1, target2]) + self.assertEqual(args.force, True) + self.assertEqual(args.single_item, True) + + +class TestRemove(TestDvc): + def test(self): + target1 = '1' + target2 = '2' + + args = parse_args(['remove', + target1, + target2]) + + self.assertIsInstance(args.func(args), CmdRemove) + self.assertEqual(args.targets, [target1, target2]) + + +class TestAdd(TestDvc): + def test(self): + target1 = '1' + target2 = '2' + + args = parse_args(['add', + target1, + target2]) + + self.assertIsInstance(args.func(args), CmdAdd) + self.assertEqual(args.targets, [target1, target2]) + + +class TestLock(TestDvc): + def test(self): + target1 = '1' + target2 = '2' + + args = parse_args(['lock', + target1, + target2, + '-u', '--unlock']) + + self.assertIsInstance(args.func(args), CmdLock) + self.assertEqual(args.files, [target1, target2]) + self.assertEqual(args.unlock, True) + + +class TestGC(TestDvc): + def test(self): + args = parse_args(['gc']) + self.assertIsInstance(args.func(args), CmdGC) + + +class TestConfig(TestDvc): + def test(self): + name = 'param' + value = '1' + + args = parse_args(['config', + '-u', '--unset', + name, + value]) + + self.assertIsInstance(args.func(args), CmdConfig) + self.assertEqual(args.unset, True) + self.assertEqual(args.name, name) + self.assertEqual(args.value, value) + + +class TestShowPipeline(TestDvc): + def test(self): + target1 = '1' + target2 = '2' + + args = parse_args(['show', + 'pipeline', + target1, + target2]) + + self.assertIsInstance(args.func(args), CmdShowPipeline) + self.assertEqual(args.target, [target1, target2]) + + +class TestShowWorkflow(TestDvc): + def test(self): + target = '1' + + args = parse_args(['show', + 'workflow', + '-d', '--dvc-commits', + '-a', '--all-commits', + '-m', '1', + '--max-commits', '1', + target]) + + self.assertIsInstance(args.func(args), CmdShowWorkflow) + self.assertEqual(args.target, target) + self.assertTrue(args.dvc_commits) + self.assertTrue(args.all_commits) + self.assertEqual(args.max_commits, 1) + + +class TestCheckout(TestDvc): + def test(self): + args = parse_args(['checkout']) + self.assertIsInstance(args.func(args), CmdCheckout) + + +class TestFind(TestDvc): + def test(self): + branch = 'branch' + target = 'target' + criteria = 'max' + + args = parse_args(['find', + branch, + target, + '-c', criteria, + '--criteria', criteria, + '-s', '--show-value']) + + self.assertIsInstance(args.func(args), CmdFind) + self.assertEqual(args.branch_name, branch) + self.assertEqual(args.target, target) + self.assertEqual(args.criteria, criteria) + self.assertTrue(args.show_value) + + +class TestFsck(TestDvc): + def test(self): + target1 = 'target1' + target2 = 'target2' + + args = parse_args(['fsck', + '-p', '--physical', + target1, + target2]) + + self.assertIsInstance(args.func(args), CmdFsck) + self.assertTrue(args.physical) + self.assertEqual(args.targets, [target1, target2])