partial resolve, tests

This commit is contained in:
Jesse Bannon 2023-11-22 18:24:58 -08:00
parent f1e2984702
commit 465c949f5b
2 changed files with 62 additions and 46 deletions

View file

@ -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()}

View file

@ -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")}