Yaml error handling (#45)
This commit is contained in:
parent
f3c06ec15c
commit
ec1cc534ea
7 changed files with 92 additions and 10 deletions
|
|
@ -22,7 +22,7 @@ subscription_parser.add_argument(
|
||||||
metavar="SUBPATH",
|
metavar="SUBPATH",
|
||||||
nargs="*",
|
nargs="*",
|
||||||
help="path to subscription files, uses subscriptions.yaml if not provided",
|
help="path to subscription files, uses subscriptions.yaml if not provided",
|
||||||
default="subscriptions.yaml",
|
default=["subscriptions.yaml"],
|
||||||
)
|
)
|
||||||
###################################################################################################
|
###################################################################################################
|
||||||
# DOWNLOAD PARSER
|
# DOWNLOAD PARSER
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import yaml
|
from ytdl_sub.utils.yaml import load_yaml
|
||||||
|
|
||||||
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
||||||
from ytdl_sub.validators.validators import LiteralDictValidator
|
from ytdl_sub.validators.validators import LiteralDictValidator
|
||||||
from ytdl_sub.validators.validators import StringValidator
|
from ytdl_sub.validators.validators import StringValidator
|
||||||
|
|
@ -56,7 +55,5 @@ class ConfigFile(StrictDictValidator):
|
||||||
-------
|
-------
|
||||||
Config file validator
|
Config file validator
|
||||||
"""
|
"""
|
||||||
# TODO: Create separate yaml file loader class
|
config_dict = load_yaml(file_path=config_path)
|
||||||
with open(config_path, "r", encoding="utf-8") as file:
|
|
||||||
config_dict = yaml.safe_load(file)
|
|
||||||
return ConfigFile.from_dict(config_dict)
|
return ConfigFile.from_dict(config_dict)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ from typing import Optional
|
||||||
from typing import Tuple
|
from typing import Tuple
|
||||||
from typing import Type
|
from typing import Type
|
||||||
|
|
||||||
import yaml
|
|
||||||
from mergedeep import mergedeep
|
from mergedeep import mergedeep
|
||||||
|
|
||||||
from ytdl_sub.config.config_file import ConfigFile
|
from ytdl_sub.config.config_file import ConfigFile
|
||||||
|
|
@ -20,6 +19,7 @@ from ytdl_sub.downloaders.downloader import DownloaderValidator
|
||||||
from ytdl_sub.plugins.plugin import Plugin
|
from ytdl_sub.plugins.plugin import Plugin
|
||||||
from ytdl_sub.plugins.plugin import PluginOptions
|
from ytdl_sub.plugins.plugin import PluginOptions
|
||||||
from ytdl_sub.utils.exceptions import StringFormattingVariableNotFoundException
|
from ytdl_sub.utils.exceptions import StringFormattingVariableNotFoundException
|
||||||
|
from ytdl_sub.utils.yaml import load_yaml
|
||||||
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
from ytdl_sub.validators.strict_dict_validator import StrictDictValidator
|
||||||
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
|
from ytdl_sub.validators.string_formatter_validators import OverridesStringFormatterValidator
|
||||||
from ytdl_sub.validators.validators import DictValidator
|
from ytdl_sub.validators.validators import DictValidator
|
||||||
|
|
@ -280,9 +280,7 @@ class Preset(StrictDictValidator):
|
||||||
-------
|
-------
|
||||||
List of presets, for each one in the subscription yaml
|
List of presets, for each one in the subscription yaml
|
||||||
"""
|
"""
|
||||||
# TODO: Create separate yaml file loader class
|
subscription_dict = load_yaml(file_path=subscription_path)
|
||||||
with open(subscription_path, "r", encoding="utf-8") as file:
|
|
||||||
subscription_dict = yaml.safe_load(file)
|
|
||||||
|
|
||||||
subscriptions: List["Preset"] = []
|
subscriptions: List["Preset"] = []
|
||||||
for subscription_key, subscription_object in subscription_dict.items():
|
for subscription_key, subscription_object in subscription_dict.items():
|
||||||
|
|
|
||||||
|
|
@ -12,3 +12,11 @@ class StringFormattingVariableNotFoundException(StringFormattingException):
|
||||||
|
|
||||||
class DownloadArchiveException(ValueError):
|
class DownloadArchiveException(ValueError):
|
||||||
"""Any user or file errors caused by download archive or mapping files"""
|
"""Any user or file errors caused by download archive or mapping files"""
|
||||||
|
|
||||||
|
|
||||||
|
class FileNotFoundException(ValidationException):
|
||||||
|
"""Any user file that's expected to exist, but is not found"""
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidYamlException(ValidationException):
|
||||||
|
"""User yaml that is invalid"""
|
||||||
|
|
|
||||||
38
src/ytdl_sub/utils/yaml.py
Normal file
38
src/ytdl_sub/utils/yaml.py
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
import os.path
|
||||||
|
from typing import Dict
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
from yaml import YAMLError
|
||||||
|
|
||||||
|
from ytdl_sub.utils.exceptions import FileNotFoundException
|
||||||
|
from ytdl_sub.utils.exceptions import InvalidYamlException
|
||||||
|
|
||||||
|
|
||||||
|
def load_yaml(file_path: str) -> Dict:
|
||||||
|
"""
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
file_path
|
||||||
|
Path of the file
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Dict representation of the yaml file
|
||||||
|
|
||||||
|
Raises
|
||||||
|
------
|
||||||
|
FileNotFoundException
|
||||||
|
The file does not exist
|
||||||
|
InvalidYamlException
|
||||||
|
The file has invalid yaml
|
||||||
|
"""
|
||||||
|
if not os.path.isfile(file_path):
|
||||||
|
raise FileNotFoundException(f"The file '{file_path}' does not exist.")
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(file_path, "r", encoding="utf-8") as file:
|
||||||
|
return yaml.safe_load(file)
|
||||||
|
except YAMLError as yaml_exception:
|
||||||
|
raise InvalidYamlException(
|
||||||
|
f"'{file_path}' has invalid YAML, copy-paste it into a YAML checker to find the issue."
|
||||||
|
) from yaml_exception
|
||||||
0
tests/unit/utils/__init__.py
Normal file
0
tests/unit/utils/__init__.py
Normal file
41
tests/unit/utils/test_yaml.py
Normal file
41
tests/unit/utils/test_yaml.py
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from ytdl_sub.utils.exceptions import FileNotFoundException
|
||||||
|
from ytdl_sub.utils.exceptions import InvalidYamlException
|
||||||
|
from ytdl_sub.utils.yaml import load_yaml
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def bad_yaml():
|
||||||
|
return """
|
||||||
|
this:
|
||||||
|
is:
|
||||||
|
bad:
|
||||||
|
asdf:
|
||||||
|
bad :
|
||||||
|
:yaml
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def bad_yaml_file_path(bad_yaml):
|
||||||
|
with tempfile.NamedTemporaryFile(suffix=".yaml") as tmp_file:
|
||||||
|
tmp_file.write(bad_yaml.encode("utf-8"))
|
||||||
|
tmp_file.flush()
|
||||||
|
yield 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):
|
||||||
|
with pytest.raises(
|
||||||
|
InvalidYamlException,
|
||||||
|
match=f"'{bad_yaml_file_path}' has invalid YAML, copy-paste it into a YAML checker to find the issue.",
|
||||||
|
):
|
||||||
|
load_yaml(file_path=bad_yaml_file_path)
|
||||||
Loading…
Reference in a new issue