Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 14 additions & 7 deletions dvc/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ class Config(object): # pylint: disable=too-many-instance-attributes

def __init__(self, dvc_dir=None, validate=True):
self.dvc_dir = dvc_dir
self.validate = validate
self.should_validate = validate

if not dvc_dir:
try:
Expand Down Expand Up @@ -382,14 +382,10 @@ def load(self):
c = self._lower(c)
self.config.merge(c)

if not self.validate:
if not self.should_validate:
return

d = self.config.dict()
try:
d = self.COMPILED_SCHEMA(d)
except Invalid as exc:
raise ConfigError(str(exc)) from exc
d = self.validate(self.config)
self.config = configobj.ConfigObj(d, write_empty_values=True)

def save(self, config=None):
Expand Down Expand Up @@ -427,6 +423,12 @@ def _save(config):
raise
config.write()

def validate(self, config):
try:
return self.COMPILED_SCHEMA(config.dict())
except Invalid as exc:
raise ConfigError(str(exc)) from exc

def unset(self, section, opt=None, level=None, force=False):
"""Unsets specified option and/or section in the config.

Expand Down Expand Up @@ -491,6 +493,11 @@ def set(self, section, opt, value, level=None, force=True):
)

config[section][opt] = value

result = copy.deepcopy(self.config)
result.merge(config)
self.validate(result)

self.save(config)

def get(self, section, opt=None, level=None):
Expand Down
20 changes: 16 additions & 4 deletions tests/func/test_config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import pytest
import configobj

from dvc.main import main
from dvc.config import Config, ConfigError
from tests.basic_env import TestDvc


Expand Down Expand Up @@ -33,11 +35,11 @@ def test_root(self):
self.assertEqual(ret, 0)

def _do_test(self, local=False):
section = "setsection"
field = "setfield"
section = "core"
field = "analytics"
section_field = "{}.{}".format(section, field)
value = "setvalue"
newvalue = "setnewvalue"
value = "True"
newvalue = "False"

base = ["config"]
if local:
Expand Down Expand Up @@ -83,3 +85,13 @@ def test_non_existing(self):

ret = main(["config", "core.non_existing_field", "-u"])
self.assertEqual(ret, 251)


def test_set_invalid_key(dvc):
with pytest.raises(ConfigError, match=r"extra keys not allowed"):
dvc.config.set("core", "invalid.key", "value")


def test_merging_two_levels(dvc):
dvc.config.set('remote "test"', "url", "https://example.com")
dvc.config.set('remote "test"', "password", "1", level=Config.LEVEL_LOCAL)
4 changes: 2 additions & 2 deletions tests/func/test_remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def test(self):
self.assertEqual(main(["remote", "list"]), 0)

self.assertEqual(
main(["remote", "modify", remotes[0], "option", "value"]), 0
main(["remote", "modify", remotes[0], "checksum_jobs", "1"]), 0
)
self.assertEqual(main(["remote", "remove", remotes[0]]), 0)

Expand Down Expand Up @@ -113,7 +113,7 @@ def test(self):

class TestRemoteRemove(TestDvc):
def test(self):
ret = main(["config", "core.jobs", "1"])
ret = main(["config", "core.checksum_jobs", "1"])
self.assertEqual(ret, 0)

remote = "mys3"
Expand Down