good state of things
This commit is contained in:
parent
4b43d6f7c7
commit
4bdbb27b63
8 changed files with 179 additions and 98 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
131
tests/unit/config/test_config_file.py
Normal file
131
tests/unit/config/test_config_file.py
Normal 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",
|
||||
)
|
||||
|
|
@ -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},
|
||||
},
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue