diff --git a/dvc/command/status.py b/dvc/command/status.py index f02010778..75cbd9565 100644 --- a/dvc/command/status.py +++ b/dvc/command/status.py @@ -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 diff --git a/dvc/utils/serialize/_yaml.py b/dvc/utils/serialize/_yaml.py index 773853084..f913fa790 100644 --- a/dvc/utils/serialize/_yaml.py +++ b/dvc/utils/serialize/_yaml.py @@ -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): diff --git a/tests/unit/utils/serialize/__init__.py b/tests/unit/utils/serialize/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/unit/utils/serialize/test_yaml.py b/tests/unit/utils/serialize/test_yaml.py new file mode 100644 index 000000000..0240bdc55 --- /dev/null +++ b/tests/unit/utils/serialize/test_yaml.py @@ -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")