[BUGFIX] Fix nested parents with multiple parents (#255)

This commit is contained in:
Jesse Bannon 2022-09-29 00:09:56 -07:00 committed by GitHub
parent 06dffdb763
commit 4b6add06e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 53 additions and 33 deletions

View file

@ -277,46 +277,60 @@ class Preset(StrictDictValidator):
for validator_value in validator.dict.values():
self.__validate_override_string_formatter_validator(validator_value)
def _get_presets_to_merge(
self, parent_presets: str | List[str], seen_presets: List[str], config: ConfigFile
) -> List[Dict]:
presets_to_merge: List[Dict] = []
if isinstance(parent_presets, str):
parent_presets = [parent_presets]
for parent_preset in reversed(parent_presets):
# Make sure we do not hit an infinite loop
if parent_preset in seen_presets:
raise self._validation_exception(
f"preset loop detected with the preset '{parent_preset}'"
)
# Make sure the parent preset actually exists
if parent_preset not in config.presets.keys:
raise self._validation_exception(
f"preset '{parent_preset}' does not exist in the provided config. "
f"Available presets: {', '.join(config.presets.keys)}"
)
parent_preset_dict = copy.deepcopy(config.presets.dict[parent_preset])
presets_to_merge.append(parent_preset_dict)
if "preset" in parent_preset_dict:
presets_to_merge.extend(
self._get_presets_to_merge(
parent_presets=parent_preset_dict["preset"],
seen_presets=seen_presets + [parent_preset],
config=config,
)
)
return presets_to_merge
def __merge_parent_preset_dicts_if_present(self, config: ConfigFile):
parent_preset_validator = self._validate_key_if_present(
key="preset", validator=StringListValidator
)
if parent_preset_validator is None:
return
presets_to_merge: List[Dict] = []
for parent_preset in [preset.value for preset in parent_preset_validator.list]:
sub_parent_presets: Dict[str, Dict] = {}
while parent_preset:
# Make sure the parent preset actually exists
if parent_preset not in config.presets.keys:
raise self._validation_exception(
f"preset '{parent_preset}' does not exist in the provided config. "
f"Available presets: {', '.join(config.presets.keys)}"
)
# Make sure we do not hit an infinite loop
if parent_preset in sub_parent_presets:
raise self._validation_exception(
f"preset loop detected with the preset '{parent_preset}'"
)
parent_preset_dict = copy.deepcopy(config.presets.dict[parent_preset])
sub_parent_presets[parent_preset] = parent_preset_dict
parent_preset = parent_preset_dict.get("preset")
# Extend reversed, so top-most parents are first
if sub_parent_presets:
presets_to_merge.extend(reversed(sub_parent_presets.values()))
# Append this preset (the subscription) last
presets_to_merge.append(copy.deepcopy(self._value))
# Get list of all parent presets in depth-first search order, beginning with this preset
presets_to_merge: List[Dict] = [copy.deepcopy(self._value)] + self._get_presets_to_merge(
parent_presets=[preset.value for preset in parent_preset_validator.list],
seen_presets=[],
config=config,
)
# Merge all presets
self._value = mergedeep.merge({}, *presets_to_merge, strategy=mergedeep.Strategy.ADDITIVE)
self._value = mergedeep.merge(
{}, *reversed(presets_to_merge), strategy=mergedeep.Strategy.ADDITIVE
)
def __init__(self, config: ConfigFile, name: str, value: Any):
super().__init__(name=name, value=value)

View file

@ -32,6 +32,7 @@ def config_file() -> ConfigFile:
"tags": {"key-2": "preset_2", "key-3": "preset_2"},
}
},
"parent_preset_3": {"preset": ["parent_preset_1", "parent_preset_2"]},
"preset_self_loop": {"preset": "preset_self_loop"},
"preset_loop_0": {"preset": "preset_loop_1"},
"preset_loop_1": {"preset": "preset_loop_0"},
@ -113,12 +114,17 @@ class TestPreset:
assert tags_string_dict == {"key-1": "preset_0", "key-2": "this-preset"}
def test_preset_multiple_parents(self, config_file, output_options, youtube_video):
@pytest.mark.parametrize(
"preset_value", [["parent_preset_1", "parent_preset_2"], "parent_preset_3"]
)
def test_preset_multiple_parents(
self, config_file, output_options, youtube_video, preset_value
):
preset = Preset(
config=config_file,
name="test",
value={
"preset": ["parent_preset_1", "parent_preset_2"],
"preset": preset_value,
"youtube": youtube_video,
"output_options": output_options,
"nfo_tags": {"tags": {"key-3": "this-preset"}},