try to simplify script

This commit is contained in:
Jesse Bannon 2023-11-22 23:40:17 -08:00
parent 54a034d4a7
commit f8a2f03130
3 changed files with 25 additions and 49 deletions

View file

@ -181,13 +181,18 @@ class Script:
self._ensure_custom_function_usage_num_input_arguments_valid() self._ensure_custom_function_usage_num_input_arguments_valid()
def resolve( def resolve(
self, pre_resolved_variables: Optional[Dict[str, Resolvable]] = None self,
pre_resolved_variables: Optional[Dict[str, Resolvable]] = None,
unresolvable: Optional[Set[str]] = None,
) -> Dict[str, Resolvable]: ) -> Dict[str, Resolvable]:
""" """
Parameters Parameters
---------- ----------
pre_resolved_variables pre_resolved_variables
Optional variables that have been resolved elsewhere and could be used in this script Optional variables that have been resolved elsewhere and could be used in this script
unresolvable
Variables that cannot be resolved, forcing any variable that depends on it to not be
resolved.
Returns Returns
------- -------
@ -197,60 +202,26 @@ class Script:
Variable(name): ast for name, ast in self._variables.items() Variable(name): ast for name, ast in self._variables.items()
} }
unresolvable_variables: Set[Variable] = set(Variable(var) for var in (unresolvable or {}))
resolved_variables: Dict[Variable, Resolvable] = { resolved_variables: Dict[Variable, Resolvable] = {
Variable(name): value for name, value in (pre_resolved_variables or {}).items() Variable(name): value for name, value in (pre_resolved_variables or {}).items()
} }
unresolved_variables: Set[Variable] = set(variables.keys()) - set(resolved_variables.keys()) unresolved_variables: Set[Variable] = (
set(variables.keys()) - set(resolved_variables.keys()) - unresolvable_variables
)
while unresolved_variables: while unresolved_variables:
unresolved_count: int = len(unresolved_variables) unresolved_count: int = len(unresolved_variables)
for variable in copy.deepcopy(unresolved_variables): for variable in copy.deepcopy(unresolved_variables):
if not variables[variable].has_variable_dependency( # If the variable's variable dependencies contain an unresolvable variable,
resolved_variables=resolved_variables # declare it as unresolvable and continue
): if variables[variable].contains(unresolvable_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()}
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) unresolvable_variables.add(variable)
unresolved_variables.remove(variable) unresolved_variables.remove(variable)
elif not variables[variable].has_variable_dependency(
resolved_variables=resolved_variables # Otherwise, resolve it
): elif not variables[variable].is_subset_of(variables=resolved_variables.keys()):
resolved_variables[variable] = variables[variable].resolve( resolved_variables[variable] = variables[variable].resolve(
resolved_variables=resolved_variables, resolved_variables=resolved_variables,
custom_functions=self._functions, custom_functions=self._functions,

View file

@ -2,6 +2,7 @@ from abc import ABC
from abc import abstractmethod from abc import abstractmethod
from dataclasses import dataclass from dataclasses import dataclass
from typing import Dict from typing import Dict
from typing import Iterable
from typing import List from typing import List
from typing import Set from typing import Set
from typing import final from typing import final
@ -94,10 +95,14 @@ class VariableDependency(ABC):
raise UNREACHABLE raise UNREACHABLE
@final @final
def has_variable_dependency(self, resolved_variables: Dict[Variable, Resolvable]) -> bool: def is_subset_of(self, variables: Iterable[Variable]) -> bool:
""" """
Returns Returns
------- -------
True if variable dependency. False otherwise. True if variable dependency. False otherwise.
""" """
return not self.variables.issubset(set(resolved_variables.keys())) return not self.variables.issubset(variables)
@final
def contains(self, variables: Iterable[Variable]) -> bool:
return len(self.variables.intersection(variables)) > 0

View file

@ -26,7 +26,7 @@ class TestScript:
"bb": "b", "bb": "b",
"cc": "{%custom_func(aa, bb)}", "cc": "{%custom_func(aa, bb)}",
} }
).partial_resolve(unresolvable={"bb"}) == {"aa": String("a")} ).resolve(unresolvable={"bb"}) == {"aa": String("a")}
def test_partial_update_script(self): def test_partial_update_script(self):
script = Script( script = Script(
@ -37,7 +37,7 @@ class TestScript:
} }
) )
overrides = script.partial_resolve(unresolvable={"entry"}) overrides = script.resolve(unresolvable={"entry"})
assert overrides == {"override": String("hi")} assert overrides == {"override": String("hi")}
entry_map = ResolvedMap({String("title"): String("the title")}) entry_map = ResolvedMap({String("title"): String("the title")})