From f4807aa9a4ddc189d7b2faf2595b6bf3af471a5c Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Tue, 14 Mar 2023 23:06:51 -0700 Subject: [PATCH] [BUGFIX] Do not load YAML unless dict is returned (#541) --- src/ytdl_sub/utils/yaml.py | 7 +++++- tests/unit/utils/test_yaml.py | 46 +++++++++++++++++++++++++++++++++-- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/src/ytdl_sub/utils/yaml.py b/src/ytdl_sub/utils/yaml.py index 92e75401..58c8d972 100644 --- a/src/ytdl_sub/utils/yaml.py +++ b/src/ytdl_sub/utils/yaml.py @@ -36,13 +36,18 @@ def load_yaml(file_path: str | Path) -> Dict: try: with open(file_path, "r", encoding="utf-8") as file: - return yaml.safe_load(file) + output = yaml.safe_load(file) except YAMLError as yaml_exception: logger.debug(yaml_exception) raise InvalidYamlException( f"'{file_path}' has invalid YAML, copy-paste it into a YAML checker to find the issue." ) from yaml_exception + if not isinstance(output, dict): + raise InvalidYamlException(f"'{file_path}' was specified but does not contain any YAML.") + + return output + def dump_yaml(to_dump: Dict) -> str: """ diff --git a/tests/unit/utils/test_yaml.py b/tests/unit/utils/test_yaml.py index b61cc413..fe5f2a90 100644 --- a/tests/unit/utils/test_yaml.py +++ b/tests/unit/utils/test_yaml.py @@ -35,17 +35,59 @@ def bad_yaml_file_path(bad_yaml) -> str: FileHandler.delete(tmp_file.name) +@pytest.fixture +def single_int_file_path(bad_yaml) -> str: + # Do not delete the file in the context manager - for Windows compatibility + with tempfile.NamedTemporaryFile(suffix=".yaml", delete=False) as tmp_file: + tmp_file.write("0".encode("utf-8")) + tmp_file.flush() + + try: + yield tmp_file.name + finally: + FileHandler.delete(tmp_file.name) + + +@pytest.fixture +def empty_yaml_file_path(bad_yaml) -> str: + # Do not delete the file in the context manager - for Windows compatibility + with tempfile.NamedTemporaryFile(suffix=".yaml", delete=False) as tmp_file: + pass + + try: + yield tmp_file.name + finally: + FileHandler.delete(tmp_file.name) + + def test_load_yaml_file_not_found(): file_path = "does_not_exist.yaml" with pytest.raises(FileNotFoundException, match=f"The file '{file_path}' does not exist."): load_yaml(file_path=file_path) -def test_load_yaml_invalid_syntax(bad_yaml_file_path): +def test_load_yaml_invalid_syntax(bad_yaml_file_path: str): with pytest.raises( InvalidYamlException, match=re.escape( - f"'{bad_yaml_file_path}' has invalid YAML, copy-paste it into a YAML checker to find the issue." + f"'{bad_yaml_file_path}' has invalid YAML, " + f"copy-paste it into a YAML checker to find the issue." ), ): load_yaml(file_path=bad_yaml_file_path) + + +def test_empty_yaml(empty_yaml_file_path: str): + with pytest.raises( + InvalidYamlException, + match=re.escape(f"'{empty_yaml_file_path}' was specified but does not contain any YAML."), + ): + load_yaml(file_path=empty_yaml_file_path) + + +def test_empty_yaml_only_int(single_int_file_path: str): + with pytest.raises( + InvalidYamlException, + match=re.escape(f"'{single_int_file_path}' was specified but does not contain any YAML."), + ): + load_yaml(file_path=single_int_file_path)