From 049116265ef9a08511a093338f6cb7505316111f Mon Sep 17 00:00:00 2001 From: jbannon Date: Fri, 22 Apr 2022 21:15:27 +0000 Subject: [PATCH] better error message for bad download strat --- ytdl_subscribe/config/preset.py | 44 ++++++++++++++----- .../config/preset_class_mappings.py | 15 +++++-- ytdl_subscribe/config/preset_options.py | 20 --------- .../validators/strict_dict_validator.py | 2 +- ytdl_subscribe/validators/string_datetime.py | 2 +- ytdl_subscribe/validators/validators.py | 2 +- 6 files changed, 48 insertions(+), 37 deletions(-) diff --git a/ytdl_subscribe/config/preset.py b/ytdl_subscribe/config/preset.py index 2f024401..6bdf34b4 100644 --- a/ytdl_subscribe/config/preset.py +++ b/ytdl_subscribe/config/preset.py @@ -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 PluginMapping -from ytdl_subscribe.config.preset_options import DownloadStrategyValidator from ytdl_subscribe.config.preset_options import OutputOptions from ytdl_subscribe.config.preset_options import Overrides 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 PluginOptions 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.string_formatter_validators import OverridesStringFormatterValidator from ytdl_subscribe.validators.validators import DictValidator +from ytdl_subscribe.validators.validators import StringValidator from ytdl_subscribe.validators.validators import Validator 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): _required_keys = PRESET_REQUIRED_KEYS _optional_keys = PRESET_OPTIONAL_KEYS def __validate_and_get_downloader(self, downloader_source: str) -> Type[Downloader]: - downloader_strategy = self._validate_key( - key=downloader_source, validator=DownloadStrategyValidator - ).name - - return DownloadStrategyMapping.get( - source=downloader_source, download_strategy=downloader_strategy + return self._validate_key(key=downloader_source, validator=DownloadStrategyValidator).get( + downloader_source=downloader_source ) def __validate_and_get_downloader_options( @@ -68,7 +91,7 @@ class Preset(StrictDictValidator): # Ensure there are not multiple sources, i.e. youtube and soundcloud if downloader: - raise ValidationException( + raise self._validation_exception( f"'{self._name}' can only have one of the following sources: " f"{', '.join(downloader_sources)}" ) @@ -80,7 +103,8 @@ class Preset(StrictDictValidator): # If downloader was not set, error since it is required if not downloader: - raise ValidationException( + + raise self._validation_exception( f"'{self._name} must have one of the following sources: " f"{', '.join(downloader_sources)}" ) diff --git a/ytdl_subscribe/config/preset_class_mappings.py b/ytdl_subscribe/config/preset_class_mappings.py index bbc3fa44..5fec82e7 100644 --- a/ytdl_subscribe/config/preset_class_mappings.py +++ b/ytdl_subscribe/config/preset_class_mappings.py @@ -26,7 +26,7 @@ class DownloadStrategyMapping: "channel": YoutubeChannelDownloader, }, "soundcloud": { - "albums and singles": SoundcloudAlbumsAndSinglesDownloader, + "albums_and_singles": SoundcloudAlbumsAndSinglesDownloader, }, } @@ -45,7 +45,10 @@ class DownloadStrategyMapping: Ensure the source exists """ 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 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): raise ValueError( 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 @@ -103,5 +107,8 @@ class PluginMapping: @classmethod def get(cls, plugin: str) -> Type[Plugin]: 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] diff --git a/ytdl_subscribe/config/preset_options.py b/ytdl_subscribe/config/preset_options.py index 63f82bf1..16fbd020 100644 --- a/ytdl_subscribe/config/preset_options.py +++ b/ytdl_subscribe/config/preset_options.py @@ -86,23 +86,3 @@ class OutputOptions(StrictDictValidator): raise self._validation_exception( "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 diff --git a/ytdl_subscribe/validators/strict_dict_validator.py b/ytdl_subscribe/validators/strict_dict_validator.py index ddf78ec1..417cf7a5 100644 --- a/ytdl_subscribe/validators/strict_dict_validator.py +++ b/ytdl_subscribe/validators/strict_dict_validator.py @@ -43,7 +43,7 @@ class StrictDictValidator(DictValidator): f"'{self._name}' contains the field '{object_key}' which is not allowed. " f"Allowed fields: {', '.join(self._allowed_keys)}" ) - raise ValidationException(error_msg) + raise self._validation_exception(str(error_msg)) @property def _allowed_keys(self) -> List[str]: diff --git a/ytdl_subscribe/validators/string_datetime.py b/ytdl_subscribe/validators/string_datetime.py index 043a9bd3..ec7f2acf 100644 --- a/ytdl_subscribe/validators/string_datetime.py +++ b/ytdl_subscribe/validators/string_datetime.py @@ -18,7 +18,7 @@ class StringDatetimeValidator(Validator): try: _ = datetime_from_str(self._value) except Exception as exc: - raise ValidationException(exc) from exc + raise self._validation_exception(str(exc)) @property def datetime_str(self) -> str: diff --git a/ytdl_subscribe/validators/validators.py b/ytdl_subscribe/validators/validators.py index 114682b3..63e1a49e 100644 --- a/ytdl_subscribe/validators/validators.py +++ b/ytdl_subscribe/validators/validators.py @@ -39,7 +39,7 @@ class Validator(ABC): ) def _validation_exception( - self, error_message: str, exception_class: Type[V] = ValidationException + self, error_message: str | Exception, exception_class: Type[V] = ValidationException ) -> V: """ Parameters