better error message for bad download strat

This commit is contained in:
jbannon 2022-04-22 21:15:27 +00:00
parent 24fac00064
commit 049116265e
6 changed files with 48 additions and 37 deletions

View file

@ -7,7 +7,6 @@ from typing import Type
from ytdl_subscribe.config.preset_class_mappings import DownloadStrategyMapping from ytdl_subscribe.config.preset_class_mappings import DownloadStrategyMapping
from ytdl_subscribe.config.preset_class_mappings import PluginMapping from ytdl_subscribe.config.preset_class_mappings import PluginMapping
from ytdl_subscribe.config.preset_options import DownloadStrategyValidator
from ytdl_subscribe.config.preset_options import OutputOptions from ytdl_subscribe.config.preset_options import OutputOptions
from ytdl_subscribe.config.preset_options import Overrides from ytdl_subscribe.config.preset_options import Overrides
from ytdl_subscribe.config.preset_options import YTDLOptions from ytdl_subscribe.config.preset_options import YTDLOptions
@ -16,10 +15,10 @@ from ytdl_subscribe.downloaders.downloader import DownloaderValidator
from ytdl_subscribe.plugins.plugin import Plugin from ytdl_subscribe.plugins.plugin import Plugin
from ytdl_subscribe.plugins.plugin import PluginOptions from ytdl_subscribe.plugins.plugin import PluginOptions
from ytdl_subscribe.utils.exceptions import StringFormattingVariableNotFoundException from ytdl_subscribe.utils.exceptions import StringFormattingVariableNotFoundException
from ytdl_subscribe.utils.exceptions import ValidationException
from ytdl_subscribe.validators.strict_dict_validator import StrictDictValidator from ytdl_subscribe.validators.strict_dict_validator import StrictDictValidator
from ytdl_subscribe.validators.string_formatter_validators import OverridesStringFormatterValidator from ytdl_subscribe.validators.string_formatter_validators import OverridesStringFormatterValidator
from ytdl_subscribe.validators.validators import DictValidator from ytdl_subscribe.validators.validators import DictValidator
from ytdl_subscribe.validators.validators import StringValidator
from ytdl_subscribe.validators.validators import Validator from ytdl_subscribe.validators.validators import Validator
PRESET_REQUIRED_KEYS = {"output_options"} PRESET_REQUIRED_KEYS = {"output_options"}
@ -31,17 +30,41 @@ PRESET_OPTIONAL_KEYS = {
} }
class DownloadStrategyValidator(StrictDictValidator):
"""
Ensures a download strategy exists for a source. Does not validate any more than that.
The respective Downloader's option validator will do that.
"""
# All media sources must define a download strategy
_required_keys = {"download_strategy"}
# Extra fields will be strict-validated using other StictDictValidators
_allow_extra_keys = True
def __init__(self, name: str, value: Any):
super().__init__(name=name, value=value)
self.download_strategy_name = self._validate_key(
key="download_strategy",
validator=StringValidator,
).value
def get(self, downloader_source: str) -> Type[Downloader]:
try:
return DownloadStrategyMapping.get(
source=downloader_source, download_strategy=self.download_strategy_name
)
except ValueError as value_exc:
raise self._validation_exception(error_message=value_exc)
class Preset(StrictDictValidator): class Preset(StrictDictValidator):
_required_keys = PRESET_REQUIRED_KEYS _required_keys = PRESET_REQUIRED_KEYS
_optional_keys = PRESET_OPTIONAL_KEYS _optional_keys = PRESET_OPTIONAL_KEYS
def __validate_and_get_downloader(self, downloader_source: str) -> Type[Downloader]: def __validate_and_get_downloader(self, downloader_source: str) -> Type[Downloader]:
downloader_strategy = self._validate_key( return self._validate_key(key=downloader_source, validator=DownloadStrategyValidator).get(
key=downloader_source, validator=DownloadStrategyValidator downloader_source=downloader_source
).name
return DownloadStrategyMapping.get(
source=downloader_source, download_strategy=downloader_strategy
) )
def __validate_and_get_downloader_options( def __validate_and_get_downloader_options(
@ -68,7 +91,7 @@ class Preset(StrictDictValidator):
# Ensure there are not multiple sources, i.e. youtube and soundcloud # Ensure there are not multiple sources, i.e. youtube and soundcloud
if downloader: if downloader:
raise ValidationException( raise self._validation_exception(
f"'{self._name}' can only have one of the following sources: " f"'{self._name}' can only have one of the following sources: "
f"{', '.join(downloader_sources)}" f"{', '.join(downloader_sources)}"
) )
@ -80,7 +103,8 @@ class Preset(StrictDictValidator):
# If downloader was not set, error since it is required # If downloader was not set, error since it is required
if not downloader: if not downloader:
raise ValidationException(
raise self._validation_exception(
f"'{self._name} must have one of the following sources: " f"'{self._name} must have one of the following sources: "
f"{', '.join(downloader_sources)}" f"{', '.join(downloader_sources)}"
) )

View file

@ -26,7 +26,7 @@ class DownloadStrategyMapping:
"channel": YoutubeChannelDownloader, "channel": YoutubeChannelDownloader,
}, },
"soundcloud": { "soundcloud": {
"albums and singles": SoundcloudAlbumsAndSinglesDownloader, "albums_and_singles": SoundcloudAlbumsAndSinglesDownloader,
}, },
} }
@ -45,7 +45,10 @@ class DownloadStrategyMapping:
Ensure the source exists Ensure the source exists
""" """
if source not in cls.sources(): if source not in cls.sources():
raise ValueError(f"Tried to use source '{source}' that does not exist") raise ValueError(
f"Tried to use source '{source}' which does not exist. Available sources: "
f"{', '.join(cls.sources())}"
)
@classmethod @classmethod
def source_download_strategies(cls, source: str) -> List[str]: def source_download_strategies(cls, source: str) -> List[str]:
@ -70,7 +73,8 @@ class DownloadStrategyMapping:
if download_strategy not in cls.source_download_strategies(source): if download_strategy not in cls.source_download_strategies(source):
raise ValueError( raise ValueError(
f"Tried to use download strategy '{download_strategy}' with source '{source}', " f"Tried to use download strategy '{download_strategy}' with source '{source}', "
f"which does not exist" f"which does not exist. Available download strategies: "
f"{', '.join(cls.source_download_strategies(source))}"
) )
@classmethod @classmethod
@ -103,5 +107,8 @@ class PluginMapping:
@classmethod @classmethod
def get(cls, plugin: str) -> Type[Plugin]: def get(cls, plugin: str) -> Type[Plugin]:
if plugin not in cls.plugins(): if plugin not in cls.plugins():
raise ValueError(f"Tried to use plugin '{plugin}' that does not exist") raise ValueError(
f"Tried to use plugin '{plugin}' that does not exist. Available plugins: "
f"{', '.join(cls.plugins())}"
)
return cls._MAPPING[plugin] return cls._MAPPING[plugin]

View file

@ -86,23 +86,3 @@ class OutputOptions(StrictDictValidator):
raise self._validation_exception( raise self._validation_exception(
"maintain_stale_file_deletion requires maintain_download_archive set to True" "maintain_stale_file_deletion requires maintain_download_archive set to True"
) )
class DownloadStrategyValidator(StrictDictValidator, ABC):
"""
Ensures a download strategy exists for a source. Does not validate any more than that.
The respective Downloader's option validator will do that.
"""
# All media sources must define a download strategy
_required_keys = {"download_strategy"}
# Extra fields will be strict-validated using other StictDictValidators
_allow_extra_keys = True
def __init__(self, name: str, value: Any):
super().__init__(name=name, value=value)
self.name = self._validate_key(
key="download_strategy",
validator=StringValidator,
).value

View file

@ -43,7 +43,7 @@ class StrictDictValidator(DictValidator):
f"'{self._name}' contains the field '{object_key}' which is not allowed. " f"'{self._name}' contains the field '{object_key}' which is not allowed. "
f"Allowed fields: {', '.join(self._allowed_keys)}" f"Allowed fields: {', '.join(self._allowed_keys)}"
) )
raise ValidationException(error_msg) raise self._validation_exception(str(error_msg))
@property @property
def _allowed_keys(self) -> List[str]: def _allowed_keys(self) -> List[str]:

View file

@ -18,7 +18,7 @@ class StringDatetimeValidator(Validator):
try: try:
_ = datetime_from_str(self._value) _ = datetime_from_str(self._value)
except Exception as exc: except Exception as exc:
raise ValidationException(exc) from exc raise self._validation_exception(str(exc))
@property @property
def datetime_str(self) -> str: def datetime_str(self) -> str:

View file

@ -39,7 +39,7 @@ class Validator(ABC):
) )
def _validation_exception( def _validation_exception(
self, error_message: str, exception_class: Type[V] = ValidationException self, error_message: str | Exception, exception_class: Type[V] = ValidationException
) -> V: ) -> V:
""" """
Parameters Parameters