Repository: iterative/dvc

Issue:
dvc remove not working even default tutorial  example
i was trying to replicate the [tutorial](https://blog.dataversioncontrol.com/data-version-control-tutorial-9146715eda46).

As  i have added data like below
`dvc add data/Posts.xml.tgz`

But while executing removal with below command
`dvc remove data/Posts.xml.tgz`

`Failed to obtain latest version: the JSON object must be str, not 'bytes'
Traceback (most recent call last):
  File "/home/parma/PycharmProjects/dvc_demo/venv/lib/python3.5/site-packages/dvc/command/remove.py", line 9, in run
    self.project.remove(target)
  File "/home/parma/PycharmProjects/dvc_demo/venv/lib/python3.5/site-packages/dvc/project.py", line 129, in remove
    raise StageNotFoundError(target)
dvc.project.StageNotFoundError: Stage file data/Posts.xml.tgz does not exist
`


Discussion:
Hi @analystanand !

Thank you for the feedback!
`dvc remove` works with dvc files and not regular files(as `dvc add` does). Try adding .dvc to your command. I.e.:
```
dvc remove data/Posts.xml.tgz.dvc
```
Please let us know if that helped.

We should definitely work on improving error msgs in such trivial cases. I will take a look at it shortly. Again, thank you for helping us see that.

Thanks,
Ruslan
okay, let check

I have actually refered this [dvc remove](https://dvc.org/documentation#commands_command_reference_remove) to execute it.

Also Please update the doc..
few more deprecated commands

`dvc show`
`dvc fsck`

what is the expected behaviour with `dvc remove` ?
as per understanding, It should ideally remove from the file from  "dvc tracking"(remove .dvc file) and updated `.gitignore` by removing file name.


Thanks, 
analystanand
Hi @analystanand !

Sorry for the outdated doc, we are currently working on it. Will be sure to update it for 0.9.8 release.
You could use `dvc --help` for now, it always has most up-to-date info about dvc commands.

`dvc remove` removes outputs of a specified dvcfile.

I agree, we should also have some command to remove dvc file and cleanup other stuff. Thank you for pointing that! I've added https://github.com/iterative/dvc/issues/761 to our TODO list.

Thanks,
Ruslan
Hi @efiop 
right now here 
putting it here for explaination

-  `dvc remove  filename.csv.dvc` removes files filename.csv
-  keep the filename.csv.dvc there itself
- do not remove from .gitignore
 
but beware of accidently `dvc pull` , it will come back and silently sit over there by overwriting any changes.

I am working to make some of the best practices along with dvc.
How soon can we expect 0.9.8 release?
I expect 0.9.8 to be released by the end of the next week, if everything goes as planned.

Resolving patch:
diff --git a/dvc/command/remove.py b/dvc/command/remove.py
--- a/dvc/command/remove.py
+++ b/dvc/command/remove.py
@@ -9,6 +9,6 @@ def run(self):
             try:
                 self.project.remove(target, outs_only=outs_only)
             except DvcException as ex:
-                self.project.logger.error('Failed to remove {}', ex)
+                self.project.logger.error('Failed to remove {}'.format(target), ex)
                 return 1
         return 0
diff --git a/dvc/command/repro.py b/dvc/command/repro.py
--- a/dvc/command/repro.py
+++ b/dvc/command/repro.py
@@ -1,7 +1,7 @@
 import os
 
 from dvc.command.common.base import CmdBase
-from dvc.project import ReproductionError, StageNotFoundError
+from dvc.project import ReproductionError
 from dvc.stage import Stage
 
 
@@ -23,17 +23,6 @@ def run(self):
                 self.project.logger.error(msg, ex)
                 ret = 1
                 break
-            except StageNotFoundError as ex:
-                if os.path.exists(target):
-                    msg = '\'{}\' is not a dvc file.'.format(target)
-                    dvcfile = target + Stage.STAGE_FILE_SUFFIX
-                    if os.path.exists(target) and os.path.isfile(dvcfile):
-                        msg += ' Maybe you meant \'{}\'?'.format(dvcfile)
-                else:
-                    msg = '\'{}\' does not exist.'.format(target)
-                self.project.logger.error(msg)
-                ret = 1
-                break
             except Exception as ex:
                 msg = 'Failed to reproduce \'{}\' - unexpected error'.format(target)
                 self.project.logger.error(msg, ex)
diff --git a/dvc/project.py b/dvc/project.py
--- a/dvc/project.py
+++ b/dvc/project.py
@@ -25,14 +25,18 @@ def __init__(self, msg):
         super(InitError, self).__init__(msg)
 
 
-class StageNotFoundError(DvcException):
+class NotDvcFileError(DvcException):
     def __init__(self, path):
-        msg = 'Stage file {} does not exist'.format(path)
-        super(StageNotFoundError, self).__init__(msg)
+        msg = '\'{}\' is not a DVC file'.format(path)
+        p = path + Stage.STAGE_FILE_SUFFIX
+        if Stage.is_stage_file(p):
+            msg += '. Maybe you meant \'{}\'?'.format(p)
+        super(NotDvcFileError, self).__init__(msg)
 
 
 class ReproductionError(DvcException):
     def __init__(self, dvc_file_name, ex):
+        self.path = dvc_file_name
         msg = 'Failed to reproduce \'{}\''.format(dvc_file_name)
         super(ReproductionError, self).__init__(msg, cause=ex)
 
@@ -125,7 +129,7 @@ def add(self, fname):
 
     def remove(self, target, outs_only=False):
         if not Stage.is_stage_file(target):
-            raise StageNotFoundError(target)
+            raise NotDvcFileError(target)
 
         stage = Stage.load(self, target)
         if outs_only:
@@ -166,7 +170,7 @@ def reproduce(self, target, recursive=True, force=False):
         stages = nx.get_node_attributes(self.graph(), 'stage')
         node = os.path.relpath(os.path.abspath(target), self.root_dir)
         if node not in stages:
-            raise StageNotFoundError(target)
+            raise NotDvcFileError(target)
 
         if recursive:
             return self._reproduce_stages(stages, node, force)
@@ -185,7 +189,7 @@ def _reproduce_stages(self, stages, node, force):
     def checkout(self, target=None):
         if target:
             if not Stage.is_stage_file(target):
-                raise StageNotFoundError(target)
+                raise NotDvcFileError(target)
             stages = [Stage.load(self, target)]
         else:
             self.link_state.remove_all()


Test patch:
diff --git a/tests/test_add.py b/tests/test_add.py
--- a/tests/test_add.py
+++ b/tests/test_add.py
@@ -8,7 +8,6 @@
 from dvc.stage import Stage
 from dvc.output.base import OutputAlreadyTrackedError
 from dvc.output.base import OutputDoesNotExistError, OutputIsNotFileOrDirError
-from dvc.project import StageNotFoundError
 from dvc.command.add import CmdAdd
 
 from tests.basic_env import TestDvc
diff --git a/tests/test_gc.py b/tests/test_gc.py
--- a/tests/test_gc.py
+++ b/tests/test_gc.py
@@ -5,7 +5,6 @@
 from dvc.main import main
 from dvc.utils import file_md5
 from dvc.stage import Stage
-from dvc.project import StageNotFoundError
 from dvc.command.gc import CmdGC
 
 from tests.basic_env import TestDvc
diff --git a/tests/test_remove.py b/tests/test_remove.py
--- a/tests/test_remove.py
+++ b/tests/test_remove.py
@@ -2,7 +2,7 @@
 
 from dvc.main import main
 from dvc.stage import Stage
-from dvc.project import StageNotFoundError
+from dvc.project import NotDvcFileError
 from dvc.command.remove import CmdRemove
 
 from tests.basic_env import TestDvc
@@ -26,7 +26,7 @@ def test(self):
 
 class TestRemoveNonExistentFile(TestDvc):
     def test(self):
-        with self.assertRaises(StageNotFoundError) as cx:
+        with self.assertRaises(NotDvcFileError) as cx:
             self.dvc.remove('non_existent_dvc_file')