Repository: iterative/dvc

Issue:
remote: allow modifying only existing entries
**DVC version**: `0.81.0`

Using `dvc remote modify` on a non-existing entry creates an invalid remote configuration, since it creates a remote without a URL.

```bash
dvc init --no-scm
dvc remote modify missing <option> <value>
```

Ideally, raising an error should prevent the user from introducing an invalid remote entry.

[Discord discussion](https://discordapp.com/channels/485586884165107732/485596304961962003/666411899499315221)

Discussion:

Patch:
diff --git a/dvc/remote/config.py b/dvc/remote/config.py
index 87572bd1d..b409e7eab 100644
--- a/dvc/remote/config.py
+++ b/dvc/remote/config.py
@@ -3,8 +3,7 @@ import os
 import posixpath
 from urllib.parse import urlparse
 
-from dvc.config import Config
-from dvc.config import ConfigError
+from dvc.config import Config, ConfigError
 from dvc.utils import relpath
 
 
@@ -134,6 +133,8 @@ class RemoteConfig(object):
                 break
 
     def modify(self, name, option, value, level=None):
+        self.get_settings(name)
+
         self.config.set(
             Config.SECTION_REMOTE_FMT.format(name), option, value, level=level
         )


Test patch:
diff --git a/tests/func/test_remote.py b/tests/func/test_remote.py
index 777666bd9..09674eff3 100644
--- a/tests/func/test_remote.py
+++ b/tests/func/test_remote.py
@@ -6,7 +6,7 @@ import configobj
 import pytest
 from mock import patch
 
-from dvc.config import Config
+from dvc.config import Config, ConfigError
 from dvc.exceptions import DownloadError, UploadError
 from dvc.main import main
 from dvc.path_info import PathInfo
@@ -31,10 +31,10 @@ class TestRemote(TestDvc):
 
         self.assertEqual(main(["remote", "list"]), 0)
 
-        self.assertEqual(main(["remote", "remove", remotes[0]]), 0)
         self.assertEqual(
             main(["remote", "modify", remotes[0], "option", "value"]), 0
         )
+        self.assertEqual(main(["remote", "remove", remotes[0]]), 0)
 
         self.assertEqual(main(["remote", "list"]), 0)
 
@@ -250,3 +250,10 @@ def test_raise_on_too_many_open_files(tmp_dir, dvc, tmp_path_factory, mocker):
     with pytest.raises(OSError) as e:
         dvc.push()
         assert e.errno == errno.EMFILE
+
+
+def test_modify_missing_remote(dvc):
+    remote_config = RemoteConfig(dvc.config)
+
+    with pytest.raises(ConfigError, match=r"unable to find remote section"):
+        remote_config.modify("myremote", "gdrive_client_id", "xxx")