subscription_indent_idx
This commit is contained in:
parent
50a02b2b2f
commit
745ba5114a
3 changed files with 151 additions and 8 deletions
|
|
@ -134,6 +134,7 @@ class Subscription(SubscriptionDownload):
|
||||||
value=subscriptions_dict,
|
value=subscriptions_dict,
|
||||||
config=config,
|
config=config,
|
||||||
presets=[FILE_PRESET_APPLY_KEY] if has_file_preset else [],
|
presets=[FILE_PRESET_APPLY_KEY] if has_file_preset else [],
|
||||||
|
indent_overrides=[],
|
||||||
subscription_value=file_subscription_value,
|
subscription_value=file_subscription_value,
|
||||||
).subscription_dicts()
|
).subscription_dicts()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,15 +6,54 @@ from typing import List
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
from ytdl_sub.config.config_file import ConfigFile
|
from ytdl_sub.config.config_file import ConfigFile
|
||||||
|
from ytdl_sub.config.preset_options import Overrides
|
||||||
from ytdl_sub.validators.validators import DictValidator
|
from ytdl_sub.validators.validators import DictValidator
|
||||||
|
from ytdl_sub.validators.validators import StringListValidator
|
||||||
from ytdl_sub.validators.validators import StringValidator
|
from ytdl_sub.validators.validators import StringValidator
|
||||||
from ytdl_sub.validators.validators import Validator
|
from ytdl_sub.validators.validators import Validator
|
||||||
|
|
||||||
|
|
||||||
|
def subscription_indent_variable_name(index: int) -> str:
|
||||||
|
"""
|
||||||
|
Parameters
|
||||||
|
----------
|
||||||
|
index
|
||||||
|
0th-based index
|
||||||
|
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
subscription_index_i, where i is 1-based index
|
||||||
|
"""
|
||||||
|
return f"subscription_indent_{index + 1}"
|
||||||
|
|
||||||
|
|
||||||
|
def maybe_indent_override_value(value: str) -> Optional[str]:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
Value if it is an overide [Value]. None otherwise.
|
||||||
|
"""
|
||||||
|
if value.startswith("[") and value.endswith("]"):
|
||||||
|
return value[1:-1]
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class SubscriptionOutput(Validator, ABC):
|
class SubscriptionOutput(Validator, ABC):
|
||||||
def __init__(self, name, value, presets: List[str]):
|
def __init__(self, name, value, presets: List[str], indent_overrides: List[str]):
|
||||||
super().__init__(name, value)
|
super().__init__(name, value)
|
||||||
self._presets = copy.deepcopy(presets)
|
self._presets = copy.deepcopy(presets)
|
||||||
|
self._indent_overrides = copy.deepcopy(indent_overrides)
|
||||||
|
|
||||||
|
def _indent_overrides_dict(self) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Returns
|
||||||
|
-------
|
||||||
|
indent overrides to merge with the preset dict's overrides
|
||||||
|
"""
|
||||||
|
return {
|
||||||
|
subscription_indent_variable_name(i): self._indent_overrides[i]
|
||||||
|
for i in range(len(self._indent_overrides))
|
||||||
|
}
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def subscription_dicts(self) -> Dict[str, Dict]:
|
def subscription_dicts(self) -> Dict[str, Dict]:
|
||||||
|
|
@ -26,6 +65,12 @@ class SubscriptionOutput(Validator, ABC):
|
||||||
|
|
||||||
|
|
||||||
class SubscriptionPresetDictValidator(SubscriptionOutput, DictValidator):
|
class SubscriptionPresetDictValidator(SubscriptionOutput, DictValidator):
|
||||||
|
def __init__(self, name, value, presets: List[str], indent_overrides: List[str]):
|
||||||
|
super().__init__(name=name, value=value, presets=presets, indent_overrides=indent_overrides)
|
||||||
|
|
||||||
|
_ = self._validate_key_if_present(key="preset", validator=StringListValidator, default=[])
|
||||||
|
_ = self._validate_key_if_present(key="overrides", validator=Overrides, default={})
|
||||||
|
|
||||||
def subscription_dicts(self) -> Dict[str, Dict]:
|
def subscription_dicts(self) -> Dict[str, Dict]:
|
||||||
output_dict = copy.deepcopy(self._dict)
|
output_dict = copy.deepcopy(self._dict)
|
||||||
parent_presets = output_dict.get("preset", [])
|
parent_presets = output_dict.get("preset", [])
|
||||||
|
|
@ -35,12 +80,22 @@ class SubscriptionPresetDictValidator(SubscriptionOutput, DictValidator):
|
||||||
parent_presets = [parent_presets]
|
parent_presets = [parent_presets]
|
||||||
|
|
||||||
output_dict["preset"] = parent_presets + self._presets
|
output_dict["preset"] = parent_presets + self._presets
|
||||||
|
output_dict["overrides"] = dict(
|
||||||
|
output_dict.get("overrides", {}), **self._indent_overrides_dict()
|
||||||
|
)
|
||||||
return {self._leaf_name: output_dict}
|
return {self._leaf_name: output_dict}
|
||||||
|
|
||||||
|
|
||||||
class SubscriptionValueValidator(SubscriptionOutput, StringValidator):
|
class SubscriptionValueValidator(SubscriptionOutput, StringValidator):
|
||||||
def __init__(self, name, value, presets: List[str], subscription_value: Optional[str]):
|
def __init__(
|
||||||
super().__init__(name, value, presets)
|
self,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
presets: List[str],
|
||||||
|
indent_overrides: List[str],
|
||||||
|
subscription_value: Optional[str],
|
||||||
|
):
|
||||||
|
super().__init__(name=name, value=value, presets=presets, indent_overrides=indent_overrides)
|
||||||
if subscription_value is None:
|
if subscription_value is None:
|
||||||
raise self._validation_exception(
|
raise self._validation_exception(
|
||||||
f"Subscription {name} is a string, but the subscription value "
|
f"Subscription {name} is a string, but the subscription value "
|
||||||
|
|
@ -53,7 +108,9 @@ class SubscriptionValueValidator(SubscriptionOutput, StringValidator):
|
||||||
return {
|
return {
|
||||||
self._leaf_name: {
|
self._leaf_name: {
|
||||||
"preset": self._presets,
|
"preset": self._presets,
|
||||||
"overrides": {self._subscription_value: self.value},
|
"overrides": dict(
|
||||||
|
{self._subscription_value: self.value}, **self._indent_overrides_dict()
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -64,9 +121,15 @@ class SubscriptionValidator(SubscriptionOutput):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, name, value, config: ConfigFile, presets: List[str], subscription_value: Optional[str]
|
self,
|
||||||
|
name,
|
||||||
|
value,
|
||||||
|
config: ConfigFile,
|
||||||
|
presets: List[str],
|
||||||
|
indent_overrides: List[str],
|
||||||
|
subscription_value: Optional[str],
|
||||||
):
|
):
|
||||||
super().__init__(name, value, presets)
|
super().__init__(name=name, value=value, presets=presets, indent_overrides=indent_overrides)
|
||||||
self._children: List[SubscriptionOutput] = []
|
self._children: List[SubscriptionOutput] = []
|
||||||
|
|
||||||
for key, obj in value.items():
|
for key, obj in value.items():
|
||||||
|
|
@ -78,12 +141,12 @@ class SubscriptionValidator(SubscriptionOutput):
|
||||||
f"{key} conflicts with an existing preset name and cannot be "
|
f"{key} conflicts with an existing preset name and cannot be "
|
||||||
f"used as a subscription name"
|
f"used as a subscription name"
|
||||||
)
|
)
|
||||||
|
|
||||||
self._children.append(
|
self._children.append(
|
||||||
SubscriptionValueValidator(
|
SubscriptionValueValidator(
|
||||||
name=obj_name,
|
name=obj_name,
|
||||||
value=obj,
|
value=obj,
|
||||||
presets=presets,
|
presets=presets,
|
||||||
|
indent_overrides=indent_overrides,
|
||||||
subscription_value=subscription_value,
|
subscription_value=subscription_value,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
@ -95,12 +158,29 @@ class SubscriptionValidator(SubscriptionOutput):
|
||||||
value=obj,
|
value=obj,
|
||||||
config=config,
|
config=config,
|
||||||
presets=presets + [key],
|
presets=presets + [key],
|
||||||
|
indent_overrides=indent_overrides,
|
||||||
|
subscription_value=subscription_value,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif override_value := maybe_indent_override_value(key):
|
||||||
|
self._children.append(
|
||||||
|
SubscriptionValidator(
|
||||||
|
name=obj_name,
|
||||||
|
value=obj,
|
||||||
|
config=config,
|
||||||
|
presets=presets,
|
||||||
|
indent_overrides=indent_overrides + [override_value],
|
||||||
subscription_value=subscription_value,
|
subscription_value=subscription_value,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self._children.append(
|
self._children.append(
|
||||||
SubscriptionPresetDictValidator(name=obj_name, value=obj, presets=presets)
|
SubscriptionPresetDictValidator(
|
||||||
|
name=obj_name,
|
||||||
|
value=obj,
|
||||||
|
presets=presets,
|
||||||
|
indent_overrides=indent_overrides,
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def subscription_dicts(self) -> Dict[str, Dict]:
|
def subscription_dicts(self) -> Dict[str, Dict]:
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ def preset_with_file_preset(youtube_video: Dict, output_options: Dict):
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"test_file_subscription_value": "original",
|
"test_file_subscription_value": "original",
|
||||||
"test_config_subscription_value": "original",
|
"test_config_subscription_value": "original",
|
||||||
|
"subscription_indent_1": "original_1",
|
||||||
|
"subscription_indent_2": "original_2",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"test_preset": {
|
"test_preset": {
|
||||||
|
|
@ -88,6 +90,25 @@ def preset_with_subscription_value_nested_presets(preset_with_subscription_value
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def preset_with_subscription_value_nested_presets_and_indent_variables(
|
||||||
|
preset_with_subscription_value: Dict,
|
||||||
|
):
|
||||||
|
return dict(
|
||||||
|
preset_with_subscription_value,
|
||||||
|
**{
|
||||||
|
"parent_preset_2": {
|
||||||
|
"[INDENT_1]": {
|
||||||
|
"parent_preset_1": {"test_2_1": "is_2_1_overwritten"},
|
||||||
|
"[INDENT_2]": {
|
||||||
|
"test_1": "is_1_overwritten",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_subscription_file_preset_applies(config_file: ConfigFile, preset_with_file_preset: Dict):
|
def test_subscription_file_preset_applies(config_file: ConfigFile, preset_with_file_preset: Dict):
|
||||||
with mock_load_yaml(preset_dict=preset_with_file_preset):
|
with mock_load_yaml(preset_dict=preset_with_file_preset):
|
||||||
subs = Subscription.from_file_path(config=config_file, subscription_path="mocked")
|
subs = Subscription.from_file_path(config=config_file, subscription_path="mocked")
|
||||||
|
|
@ -197,6 +218,47 @@ def test_subscription_file_value_applies_from_config_and_nested(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_subscription_file_value_applies_from_config_and_nested_and_indent_variables(
|
||||||
|
config_file_with_subscription_value: ConfigFile,
|
||||||
|
preset_with_subscription_value_nested_presets_and_indent_variables: Dict,
|
||||||
|
):
|
||||||
|
with mock_load_yaml(
|
||||||
|
preset_dict=preset_with_subscription_value_nested_presets_and_indent_variables
|
||||||
|
):
|
||||||
|
subs = Subscription.from_file_path(
|
||||||
|
config=config_file_with_subscription_value, subscription_path="mocked"
|
||||||
|
)
|
||||||
|
assert len(subs) == 4
|
||||||
|
|
||||||
|
# Test __value__ worked correctly from the config
|
||||||
|
sub_test_value = [sub for sub in subs if sub.name == "test_value"][0]
|
||||||
|
sub_1 = [sub for sub in subs if sub.name == "test_1"][0]
|
||||||
|
sub_2_1 = [sub for sub in subs if sub.name == "test_2_1"][0]
|
||||||
|
|
||||||
|
assert (
|
||||||
|
sub_test_value.overrides.dict_with_format_strings.get("subscription_indent_1")
|
||||||
|
== "original_1"
|
||||||
|
)
|
||||||
|
assert (
|
||||||
|
sub_test_value.overrides.dict_with_format_strings.get("subscription_indent_2")
|
||||||
|
== "original_2"
|
||||||
|
)
|
||||||
|
|
||||||
|
assert (
|
||||||
|
sub_1.overrides.dict_with_format_strings.get("test_config_subscription_value")
|
||||||
|
== "is_1_overwritten"
|
||||||
|
)
|
||||||
|
assert sub_1.overrides.dict_with_format_strings.get("subscription_indent_1") == "INDENT_1"
|
||||||
|
assert sub_1.overrides.dict_with_format_strings.get("subscription_indent_2") == "INDENT_2"
|
||||||
|
|
||||||
|
assert (
|
||||||
|
sub_2_1.overrides.dict_with_format_strings.get("test_config_subscription_value")
|
||||||
|
== "is_2_1_overwritten"
|
||||||
|
)
|
||||||
|
assert sub_2_1.overrides.dict_with_format_strings.get("subscription_indent_1") == "INDENT_1"
|
||||||
|
assert sub_2_1.overrides.dict_with_format_strings.get("subscription_indent_2") == "original_2"
|
||||||
|
|
||||||
|
|
||||||
def test_subscription_file_bad_value(config_file: ConfigFile):
|
def test_subscription_file_bad_value(config_file: ConfigFile):
|
||||||
with mock_load_yaml(preset_dict={"__value__": {"should be": "string"}}), pytest.raises(
|
with mock_load_yaml(preset_dict={"__value__": {"should be": "string"}}), pytest.raises(
|
||||||
ValidationException,
|
ValidationException,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue