Repository: iterative/dvc

Issue:
dvc move complains about 
**Please provide information about your setup**
DVC version(i.e. `dvc --version`), Platform and method of installation (pip, homebrew, pkg Mac, exe (Windows), DEB(Linux), RPM(Linux))

DVC version: 0.19.2
Method of installation: DEB

When I run `dvc move`, it throws me this error:
```
Error: Unexpected error: 'Stage' object has no attribute 'rel_path'
```


Discussion:
Hi @yukw777 !

I have identified the bug. Will send a patch ASAP and will release 0.19.4 right after it.

Btw, looking at the code, looks like you are trying to move a full blown stage, right? `dvc move` can only work on data sources(i.e. stages without command like those created with `dvc add`), because in general dvc can't know how it should modify your command to work with a different path. You can perform the `move` yourself, by either modifying redspective .dvc file yourself(it is a simple yaml format), or by removing the old stage and creating(`dvc run`) new stage at the new location from scratch.

Thanks,
Ruslan

Resolving patch:
diff --git a/dvc/exceptions.py b/dvc/exceptions.py
--- a/dvc/exceptions.py
+++ b/dvc/exceptions.py
@@ -29,3 +29,12 @@ def __init__(self, output, stages):
         for stage in stages:
             s += "\n    " + stage
         super(OutputDuplicationError, self).__init__(msg.format(output, s))
+
+
+class MoveNotDataSourceError(DvcException):
+    def __init__(self, path):
+        msg = "Move is not permitted for stages that are not data sources. " \
+              "You need to either move '{path}' to a new location and edit " \
+              "it by hand, or remove '{path}' and create a new one at the " \
+              "desired location."
+        super(MoveNotDataSourceError, self).__init__(msg.format(path=path))
diff --git a/dvc/project.py b/dvc/project.py
--- a/dvc/project.py
+++ b/dvc/project.py
@@ -1,6 +1,6 @@
 import os
 
-from dvc.exceptions import DvcException
+from dvc.exceptions import DvcException, MoveNotDataSourceError
 from dvc.stage import Stage
 
 
@@ -209,8 +209,7 @@ def move(self, from_path, to_path):
                         continue
 
                     if not stage.is_data_source:
-                        msg = 'Dvcfile \'{}\' is not a data source.'
-                        raise DvcException(msg.format(stage.rel_path))
+                        raise MoveNotDataSourceError(stage.relpath)
 
                     found = True
                     to_out = Output.loads_from(out.stage,


Test patch:
diff --git a/tests/test_move.py b/tests/test_move.py
--- a/tests/test_move.py
+++ b/tests/test_move.py
@@ -1,9 +1,10 @@
 import os
 
 from dvc.main import main
-from dvc.exceptions import DvcException
+from dvc.exceptions import DvcException, MoveNotDataSourceError
 
 from tests.basic_env import TestDvc
+from tests.test_repro import TestRepro
 
 
 class TestMove(TestDvc):
@@ -39,3 +40,15 @@ def test(self):
 
         ret = main(['move', 'non-existing-file', 'dst'])
         self.assertNotEqual(ret, 0)
+
+
+class TestMoveNotDataSource(TestRepro):
+    def test(self):
+        from dvc.project import Project
+
+        self.dvc = Project(self._root_dir)
+        with self.assertRaises(MoveNotDataSourceError):
+            self.dvc.move(self.file1, 'dst')
+
+        ret = main(['move', self.file1, 'dst'])
+        self.assertNotEqual(ret, 0)