recursive var names
This commit is contained in:
parent
451b3564c5
commit
5fed8a7b64
2 changed files with 68 additions and 1 deletions
|
|
@ -8,6 +8,7 @@ from ytdl_subscribe.validators.base.string_formatter_validators import (
|
||||||
from ytdl_subscribe.validators.config.overrides.overrides_validator import (
|
from ytdl_subscribe.validators.config.overrides.overrides_validator import (
|
||||||
OverridesValidator,
|
OverridesValidator,
|
||||||
)
|
)
|
||||||
|
from ytdl_subscribe.validators.exceptions import ValidationException
|
||||||
|
|
||||||
|
|
||||||
class TestEntry(object):
|
class TestEntry(object):
|
||||||
|
|
@ -68,6 +69,45 @@ class TestEntry(object):
|
||||||
== expected_string
|
== expected_string
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_entry_formatter_override_recursive(self, mock_entry):
|
||||||
|
overrides = OverridesValidator(
|
||||||
|
name="test",
|
||||||
|
value={
|
||||||
|
"level_a": "level a",
|
||||||
|
"level_b": "level b and {level_a}",
|
||||||
|
"level_c": "level c and {level_b}",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
format_string = StringFormatterValidator(
|
||||||
|
name="test", value="level d and {level_c}"
|
||||||
|
)
|
||||||
|
expected_string = "level d and level c and level b and level a"
|
||||||
|
|
||||||
|
assert (
|
||||||
|
mock_entry.apply_formatter(format_string, overrides=overrides)
|
||||||
|
== expected_string
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_entry_formatter_override_recursive_fail_cycle(self, mock_entry):
|
||||||
|
overrides = OverridesValidator(
|
||||||
|
name="test",
|
||||||
|
value={
|
||||||
|
"level_a": "{level_b}",
|
||||||
|
"level_b": "{level_a}",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
expected_error_msg = (
|
||||||
|
f"Attempted to format 'test' but failed after reaching max recursion depth of 3. "
|
||||||
|
f"Try to keep variables dependent on only one other variable."
|
||||||
|
)
|
||||||
|
|
||||||
|
format_string = StringFormatterValidator(name="test", value="{level_a}")
|
||||||
|
|
||||||
|
with pytest.raises(ValidationException, match=expected_error_msg):
|
||||||
|
_ = mock_entry.apply_formatter(format_string, overrides=overrides)
|
||||||
|
|
||||||
def test_entry_missing_kwarg(self, mock_entry):
|
def test_entry_missing_kwarg(self, mock_entry):
|
||||||
key = "dne"
|
key = "dne"
|
||||||
expected_error_msg = f"Expected '{key}' in Entry but does not exist."
|
expected_error_msg = f"Expected '{key}' in Entry but does not exist."
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
from collections import OrderedDict
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any
|
from typing import Any
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
@ -11,6 +12,7 @@ from ytdl_subscribe.validators.base.string_formatter_validators import (
|
||||||
from ytdl_subscribe.validators.config.overrides.overrides_validator import (
|
from ytdl_subscribe.validators.config.overrides.overrides_validator import (
|
||||||
OverridesValidator,
|
OverridesValidator,
|
||||||
)
|
)
|
||||||
|
from ytdl_subscribe.validators.exceptions import ValidationException
|
||||||
|
|
||||||
|
|
||||||
class Entry:
|
class Entry:
|
||||||
|
|
@ -18,6 +20,8 @@ class Entry:
|
||||||
Entry object to represent a single media object returned from yt-dlp.
|
Entry object to represent a single media object returned from yt-dlp.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
_MAX_FORMATTER_RECURSION = 3
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
Initialize the entry using ytdl metadata
|
Initialize the entry using ytdl metadata
|
||||||
|
|
@ -129,4 +133,27 @@ class Entry:
|
||||||
f"for {self.__class__.__name__}. Available fields: {available_fields}"
|
f"for {self.__class__.__name__}. Available fields: {available_fields}"
|
||||||
)
|
)
|
||||||
|
|
||||||
return formatter.format_string.format(**entry_dict)
|
format_string = formatter.format_string
|
||||||
|
variables_present = True
|
||||||
|
recursion_depth = 0
|
||||||
|
while variables_present and recursion_depth < self._MAX_FORMATTER_RECURSION:
|
||||||
|
format_string = format_string.format(**OrderedDict(entry_dict))
|
||||||
|
variables_present = (
|
||||||
|
len(
|
||||||
|
StringFormatterValidator(
|
||||||
|
name="__recursive_formatter_update__",
|
||||||
|
value=format_string,
|
||||||
|
).format_variables
|
||||||
|
)
|
||||||
|
> 0
|
||||||
|
)
|
||||||
|
recursion_depth += 1
|
||||||
|
|
||||||
|
if variables_present:
|
||||||
|
raise ValidationException(
|
||||||
|
f"Attempted to format '{formatter._name}' but failed after reaching max recursion "
|
||||||
|
f"depth of {self._MAX_FORMATTER_RECURSION}. Try to keep variables dependent on "
|
||||||
|
f"only one other variable."
|
||||||
|
)
|
||||||
|
|
||||||
|
return format_string
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue