good state of things

This commit is contained in:
Jesse Bannon 2022-10-25 22:33:18 -07:00
parent 4b43d6f7c7
commit 4bdbb27b63
8 changed files with 179 additions and 98 deletions

View file

@ -146,7 +146,7 @@ class Preset(_PresetShell):
if len(sources) > 1:
raise validation_exception(
name=name,
error_message=f"Contains the sources {', '.join(sources)}' but can only have one",
error_message=f"Contains the sources {', '.join(sources)} but can only have one",
)
# If no sources, nothing more to validate

View file

@ -1,4 +1,5 @@
import os
from typing import Any
from typing import Dict
from typing import Optional
@ -27,6 +28,15 @@ class FileConvertOptions(PluginOptions):
_required_keys = {"convert_to"}
@classmethod
def partial_validate(cls, name: str, value: Any) -> None:
"""
Partially validate file_convert
"""
if isinstance(value, dict):
value["convert_to"] = value.get("convert_to", "mp3")
_ = cls(name, value)
def __init__(self, name, value):
super().__init__(name, value)
self._convert_to = self._validate_key(key="convert_to", validator=FileTypeValidator).value

View file

@ -1,3 +1,4 @@
from typing import Any
from typing import Dict
import mediafile
@ -34,6 +35,15 @@ class MusicTagsOptions(PluginOptions):
_required_keys = {"tags"}
@classmethod
def partial_validate(cls, name: str, value: Any) -> None:
"""
Partially validate music tags
"""
if isinstance(value, dict):
value["tags"] = value.get("tags", {})
_ = cls(name, value)
def __init__(self, name, value):
super().__init__(name, value)

View file

@ -1,3 +1,4 @@
from typing import Any
from typing import Dict
from typing import List
from typing import Optional
@ -149,6 +150,15 @@ class RegexOptions(PluginOptions):
_required_keys = {"from"}
_optional_keys = {"skip_if_match_fails"}
@classmethod
def partial_validate(cls, name: str, value: Any) -> None:
"""
Partially validate regex
"""
if isinstance(value, dict):
value["from"] = value.get("from", {})
_ = cls(name, value)
def __init__(self, name, value):
super().__init__(name, value)
self._from = self._validate_key(key="from", validator=FromSourceVariablesRegex)

View file

@ -1,6 +1,7 @@
import copy
import os.path
from pathlib import Path
from typing import Any
from typing import List
from typing import Optional
from typing import Tuple
@ -67,6 +68,12 @@ class SplitByChaptersOptions(PluginOptions):
_required_keys = {"when_no_chapters"}
@classmethod
def partial_validate(cls, name: str, value: Any) -> None:
if isinstance(value, dict):
value["when_no_chapters"] = value.get("when_no_chapters", "pass")
_ = cls(name, value)
def __init__(self, name, value):
super().__init__(name, value)
self._when_no_chapters = self._validate_key(

View file

@ -1,3 +1,4 @@
from typing import Any
from typing import Dict
from ytdl_sub.entries.entry import Entry
@ -27,6 +28,15 @@ class VideoTagsOptions(PluginOptions):
_required_keys = {"tags"}
@classmethod
def partial_validate(cls, name: str, value: Any) -> None:
"""
Partially validate video tags
"""
if isinstance(value, dict):
value["tags"] = value.get("tags", {})
_ = cls(name, value)
def __init__(self, name, value):
super().__init__(name, value)
self._tags = self._validate_key(key="tags", validator=DictFormatterValidator)

View file

@ -0,0 +1,131 @@
import re
from typing import Dict
from typing import Optional
import pytest
from ytdl_sub.config.config_file import ConfigFile
from ytdl_sub.config.preset import PRESET_KEYS
from ytdl_sub.config.preset_class_mappings import PluginMapping
from ytdl_sub.utils.exceptions import ValidationException
class TestConfigFilePartiallyValidatesPresets:
@classmethod
def _partial_validate(
cls, preset_dict: Dict, expected_error_message: Optional[str] = None
) -> None:
def _config_create() -> None:
_ = ConfigFile(
name="test_partial_validate",
value={
"configuration": {"working_directory": "."},
"presets": {"partial_preset": preset_dict},
},
)
if expected_error_message:
with pytest.raises(ValidationException, match=re.escape(expected_error_message)):
_config_create()
else:
_config_create()
@pytest.mark.parametrize(
"preset_dict",
[
{"nfo_tags": {"tags": {"key-1": "preset_0"}}},
{"output_directory_nfo_tags": {"nfo_root": "test"}},
{"output_options": {"file_name": "test"}},
{"output_options": {"keep_files_after": "today", "maintain_download_archive": True}},
{"ytdl_options": {"format": "best"}},
{"overrides": {"a": "b"}},
],
)
def test_success(self, preset_dict: Dict):
self._partial_validate(preset_dict)
@pytest.mark.parametrize("plugin", PluginMapping.plugins())
def test_success__empty_plugins(self, plugin: str):
self._partial_validate({plugin: {}})
def test_error__bad_preset_section(self):
self._partial_validate(
preset_dict={"does_not_exist": "lol"},
expected_error_message="Validation error in partial_preset: "
"'partial_preset' contains the field 'does_not_exist' which is not allowed. "
f"Allowed fields: {', '.join(sorted(PRESET_KEYS))}",
)
def test_error__multiple_sources(self):
self._partial_validate(
preset_dict={"youtube": {}, "generic": {}},
expected_error_message="Validation error in partial_preset: "
"Contains the sources generic, youtube but can only have one",
)
def test_error__no_download_strategy(self):
self._partial_validate(
preset_dict={"generic": {}},
expected_error_message="Validation error in partial_preset.generic: "
"missing the required field 'download_strategy'",
)
def test_error__bad_download_strategy(self):
self._partial_validate(
preset_dict={"generic": {"download_strategy": "fail"}},
expected_error_message="Validation error in partial_preset.generic: "
"Tried to use download strategy 'fail' with source 'generic', "
"which does not exist. Available download strategies: collection, source",
)
def test_error__bad_download_strategy_args(self):
self._partial_validate(
preset_dict={"generic": {"download_strategy": "collection", "bad_key": "nope"}},
expected_error_message="Validation error in partial_preset.generic: "
"'partial_preset.generic' contains the field 'bad_key' which is not allowed. "
"Allowed fields: urls",
)
@pytest.mark.parametrize(
"preset_dict",
[
{"nfo_tags": {"tags": {"key-1": {"attributes": {"test": "2"}}}}},
{"generic": {"urls": [{"variables_to_set": {"name": "value"}}]}},
],
)
def test_partial_validate__incomplete_list_item(self, preset_dict):
with pytest.raises(ValidationException):
_ = ConfigFile(
name="test_partial_validate",
value={
"configuration": {"working_directory": "."},
"presets": {"partial_preset": preset_dict},
},
)
@pytest.mark.parametrize(
"preset_dict",
[
{"overrides": "not a dict"},
{"overrides": {"nested": {"dict": "value"}}},
{"overrides": ["list"]},
],
)
def test_error__bad_overrides(self, preset_dict):
self._partial_validate(
preset_dict=preset_dict,
expected_error_message="Validation error in partial_preset.overrides",
)
@pytest.mark.parametrize(
"preset_dict",
[
{"ytdl_options": "not a dict"},
{"ytdl_options": ["list"]},
],
)
def test_error__bad_ytdl_options(self, preset_dict):
self._partial_validate(
preset_dict=preset_dict,
expected_error_message="Validation error in partial_preset.ytdl_options",
)

View file

@ -1,11 +1,5 @@
import re
from typing import Dict
from typing import Optional
import pytest
from ytdl_sub.config.config_file import ConfigFile
from ytdl_sub.config.preset import PRESET_KEYS
from ytdl_sub.config.preset import Preset
from ytdl_sub.plugins.nfo_tags import NfoTagsOptions
from ytdl_sub.utils.exceptions import StringFormattingVariableNotFoundException
@ -206,94 +200,3 @@ class TestPreset:
},
},
)
class TestPresetPartialValidate:
@classmethod
def _partial_validate(
cls, preset_dict: Dict, expected_error_message: Optional[str] = None
) -> None:
def _config_create() -> None:
_ = ConfigFile(
name="test_partial_validate",
value={
"configuration": {"working_directory": "."},
"presets": {"partial_preset": preset_dict},
},
)
if expected_error_message:
with pytest.raises(ValidationException, match=re.escape(expected_error_message)):
_config_create()
else:
_config_create()
@pytest.mark.parametrize(
"preset_dict",
[
{"nfo_tags": {"tags": {"key-1": "preset_0"}}},
{"output_directory_nfo_tags": {"nfo_root": "test"}},
{"output_directory": {"file_name": "test"}},
{"output_directory": {"keep_files_after": "today"}},
{"ytdl_options": {"format": "best"}},
],
)
def test_success(self, preset_dict: Dict):
self._partial_validate(
preset_dict,
)
def test_error__bad_preset_section(self):
self._partial_validate(
preset_dict={"does_not_exist": "lol"},
expected_error_message="Validation error in partial_preset: "
"'partial_preset' contains the field 'does_not_exist' which is not allowed. "
f"Allowed fields: {', '.join(sorted(PRESET_KEYS))}",
)
def test_error__multiple_sources(self):
self._partial_validate(
preset_dict={"youtube": {}, "generic": {}},
expected_error_message="Validation error in partial_preset: "
"Contains the sources generic, youtube but can only have one",
)
def test_error__no_download_strategy(self):
self._partial_validate(
preset_dict={"generic": {}},
expected_error_message="Validation error in partial_preset.generic: "
"missing the required field 'download_strategy'",
)
def test_error__bad_download_strategy(self):
self._partial_validate(
preset_dict={"generic": {"download_strategy": "fail"}},
expected_error_message="Validation error in partial_preset.generic: "
"Tried to use download strategy 'fail' with source 'generic', "
"which does not exist. Available download strategies: collection, source",
)
def test_error__bad_download_strategy_args(self):
self._partial_validate(
preset_dict={"generic": {"download_strategy": "collection", "bad_key": "nope"}},
expected_error_message="Validation error in partial_preset.generic: "
"'partial_preset.generic' contains the field 'bad_key' which is not allowed. "
"Allowed fields: urls",
)
@pytest.mark.parametrize(
"preset_dict",
[
{"nfo_tags": {"tags": {"key-1": {"attributes": {"test": "2"}}}}},
{"generic": {"urls": [{"variables_to_set": {"name": "value"}}]}},
],
)
def test_partial_validate__incomplete_list_item(self, preset_dict):
with pytest.raises(ValidationException):
_ = ConfigFile(
name="test_partial_validate",
value={
"configuration": {"working_directory": "."},
"presets": {"partial_preset": preset_dict},
},
)