partial resolve, tests
This commit is contained in:
parent
f1e2984702
commit
465c949f5b
2 changed files with 62 additions and 46 deletions
|
|
@ -181,7 +181,7 @@ class Script:
|
|||
self._ensure_custom_function_usage_num_input_arguments_valid()
|
||||
|
||||
def resolve(
|
||||
self, pre_resolved_variables: Optional[Dict[Variable, Resolvable]] = None
|
||||
self, pre_resolved_variables: Optional[Dict[str, Resolvable]] = None
|
||||
) -> Dict[str, Resolvable]:
|
||||
"""
|
||||
Parameters
|
||||
|
|
@ -197,10 +197,10 @@ class Script:
|
|||
Variable(name): ast for name, ast in self._variables.items()
|
||||
}
|
||||
|
||||
unresolved_variables: Set[Variable] = set(variables.keys())
|
||||
resolved_variables: Dict[Variable, Resolvable] = (
|
||||
pre_resolved_variables if pre_resolved_variables else {}
|
||||
)
|
||||
resolved_variables: Dict[Variable, Resolvable] = {
|
||||
Variable(name): value for name, value in (pre_resolved_variables or {}).items()
|
||||
}
|
||||
unresolved_variables: Set[Variable] = set(variables.keys()) - set(resolved_variables.keys())
|
||||
|
||||
while unresolved_variables:
|
||||
unresolved_count: int = len(unresolved_variables)
|
||||
|
|
@ -221,3 +221,45 @@ class Script:
|
|||
raise UNREACHABLE
|
||||
|
||||
return {variable.name: resolvable for variable, resolvable in resolved_variables.items()}
|
||||
|
||||
def partial_resolve(self, unresolvable: Set[str]) -> Dict[str, Resolvable]:
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
unresolvable
|
||||
Variables that cannot be resolved
|
||||
|
||||
Returns
|
||||
-------
|
||||
Dict of resolved values
|
||||
"""
|
||||
variables: Dict[Variable, SyntaxTree] = {
|
||||
Variable(name): ast for name, ast in self._variables.items()
|
||||
}
|
||||
|
||||
unresolvable_variables: Set[Variable] = set(Variable(var) for var in unresolvable)
|
||||
unresolved_variables: Set[Variable] = set(variables.keys()) - unresolvable_variables
|
||||
resolved_variables: Dict[Variable, Resolvable] = {}
|
||||
|
||||
while unresolved_variables:
|
||||
unresolved_count: int = len(unresolved_variables)
|
||||
|
||||
for variable in copy.deepcopy(unresolved_variables):
|
||||
if variables[variable].variables.intersection(unresolvable_variables):
|
||||
unresolvable_variables.add(variable)
|
||||
unresolved_variables.remove(variable)
|
||||
elif not variables[variable].has_variable_dependency(
|
||||
resolved_variables=resolved_variables
|
||||
):
|
||||
resolved_variables[variable] = variables[variable].resolve(
|
||||
resolved_variables=resolved_variables,
|
||||
custom_functions=self._functions,
|
||||
)
|
||||
unresolved_variables.remove(variable)
|
||||
|
||||
if len(unresolved_variables) == unresolved_count:
|
||||
# Implies a cycle within the variables. Should never reach
|
||||
# since cycles are detected in __init__
|
||||
raise UNREACHABLE
|
||||
|
||||
return {variable.name: resolvable for variable, resolvable in resolved_variables.items()}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,9 @@
|
|||
import re
|
||||
|
||||
import pytest
|
||||
|
||||
from ytdl_sub.script.script import Script
|
||||
from ytdl_sub.script.types.resolvable import String
|
||||
from ytdl_sub.script.utils.exceptions import CycleDetected
|
||||
|
||||
|
||||
class TestSyntaxTree:
|
||||
def test_custom_function(self):
|
||||
class TestScript:
|
||||
def test_pre_resolved(self):
|
||||
assert Script(
|
||||
{
|
||||
"%custom_func": "return {[$0, $1]}",
|
||||
|
|
@ -16,39 +11,18 @@ class TestSyntaxTree:
|
|||
"bb": "b",
|
||||
"cc": "{%custom_func(aa, bb)}",
|
||||
}
|
||||
).resolve() == {"aa": String("a"), "bb": String("b"), "cc": String('return ["a", "b"]')}
|
||||
|
||||
def test_simple(self):
|
||||
assert Script({"a": "a", "b": "{b_}", "b_": "b"}).resolve() == {
|
||||
"a": String("a"),
|
||||
"b": String("b"),
|
||||
"b_": String("b"),
|
||||
).resolve(pre_resolved_variables={"bb": String("bb_override")}) == {
|
||||
"aa": String("a"),
|
||||
"bb": String("bb_override"),
|
||||
"cc": String('return ["a", "bb_override"]'),
|
||||
}
|
||||
|
||||
def test_multiple_variables(self):
|
||||
assert Script({"a": "a", "b": "b", "b_": " {a} {b} "}).resolve() == {
|
||||
"a": String("a"),
|
||||
"b": String("b"),
|
||||
"b_": String(" a b "),
|
||||
}
|
||||
|
||||
def test_simple_with_function(self):
|
||||
assert Script({"a": "a", "b": "{%capitalize(b_)}", "b_": "b"}).resolve() == {
|
||||
"a": String("a"),
|
||||
"b": String("B"),
|
||||
"b_": String("b"),
|
||||
}
|
||||
|
||||
def test_simple_cycle(self):
|
||||
with pytest.raises(
|
||||
CycleDetected,
|
||||
match=re.escape("Cycle detected within these variables: " "a -> b -> a"),
|
||||
):
|
||||
Script({"a": "{b}", "b": "{a}"}).resolve()
|
||||
|
||||
def test_simple_cycle_with_function(self):
|
||||
with pytest.raises(
|
||||
CycleDetected,
|
||||
match=re.escape("Cycle detected within these variables: " "b -> b_ -> b"),
|
||||
):
|
||||
Script({"b": "{%capitalize(b_)}", "b_": "{b}"}).resolve()
|
||||
def test_partial_resolve(self):
|
||||
assert Script(
|
||||
{
|
||||
"%custom_func": "return {[$0, $1]}",
|
||||
"aa": "a",
|
||||
"bb": "b",
|
||||
"cc": "{%custom_func(aa, bb)}",
|
||||
}
|
||||
).partial_resolve(unresolvable={"bb"}) == {"aa": String("a")}
|
||||
|
|
|
|||
Loading…
Reference in a new issue