yaml: wrap ruamel's DuplicateKeyError (#4668)

* yaml: wrap ruamel's DuplicateKeyError

Unfortunately ruamel's exception doesn't contain much info that we could
reuse, so we can only reasonably extract the exc.problem and have
something like:

```
ERROR: failed to obtain data status - unable to read: 'dvc.yaml', found
duplicate key "metrics" with value "[]" (original value: "[]")
```

Fixes #4664

* status: remove unneeded error prefix
This commit is contained in:
Ruslan Kuprieiev
2020-10-05 23:02:59 +03:00
committed by GitHub
parent 3ffb6320ac
commit 3878c50ea8
4 changed files with 30 additions and 5 deletions
+1 -1
View File
@@ -72,6 +72,6 @@ class CmdDataStatus(CmdDataBase):
logger.info(self.UP_TO_DATE_MSG)
except DvcException:
logger.exception("failed to obtain data status")
logger.exception("")
return 1
return 0
+15 -4
View File
@@ -4,12 +4,17 @@ from contextlib import contextmanager
from funcy import reraise
from ruamel.yaml import YAML
from ruamel.yaml.error import YAMLError
from ruamel.yaml.constructor import DuplicateKeyError
from ruamel.yaml.error import YAMLError as _YAMLError
from ._common import ParseError, _dump_data, _load_data, _modify_data
class YAMLFileCorruptedError(ParseError):
class YAMLError(ParseError):
pass
class YAMLFileCorruptedError(YAMLError):
def __init__(self, path):
super().__init__(path, "YAML file structure is corrupted")
@@ -20,8 +25,14 @@ def load_yaml(path, tree=None):
def parse_yaml(text, path, typ="safe"):
yaml = YAML(typ=typ)
with reraise(YAMLError, YAMLFileCorruptedError(path)):
return yaml.load(text) or {}
try:
with reraise(_YAMLError, YAMLFileCorruptedError(path)):
return yaml.load(text) or {}
except DuplicateKeyError as exc:
# NOTE: unfortunately this one doesn't inherit from YAMLError, so we
# have to catch it by-hand. See
# https://yaml.readthedocs.io/en/latest/api.html#duplicate-keys
raise YAMLError(path, exc.problem)
def parse_yaml_for_update(text, path):
+14
View File
@@ -0,0 +1,14 @@
import pytest
from dvc.utils.serialize._yaml import YAMLError, parse_yaml
def test_parse_yaml_duplicate_key_error():
text = """\
mykey:
- foo
mykey:
- bar
"""
with pytest.raises(YAMLError, match='found duplicate key "mykey"'):
parse_yaml(text, "mypath")