From f8a2f03130f70ecb16b2a0d2bb7e6aab8a0d6045 Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Wed, 22 Nov 2023 23:40:17 -0800 Subject: [PATCH] try to simplify script --- src/ytdl_sub/script/script.py | 61 +++++-------------- .../script/types/variable_dependency.py | 9 ++- tests/unit/script/test_script.py | 4 +- 3 files changed, 25 insertions(+), 49 deletions(-) diff --git a/src/ytdl_sub/script/script.py b/src/ytdl_sub/script/script.py index c151f984..b8a70f72 100644 --- a/src/ytdl_sub/script/script.py +++ b/src/ytdl_sub/script/script.py @@ -181,13 +181,18 @@ class Script: self._ensure_custom_function_usage_num_input_arguments_valid() 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]: """ Parameters ---------- pre_resolved_variables 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 ------- @@ -197,60 +202,26 @@ class Script: 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] = { 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: unresolved_count: int = len(unresolved_variables) for variable in copy.deepcopy(unresolved_variables): - if 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()} - - 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): + # If the variable's variable dependencies contain an unresolvable variable, + # declare it as unresolvable and continue + if variables[variable].contains(unresolvable_variables): unresolvable_variables.add(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=resolved_variables, custom_functions=self._functions, diff --git a/src/ytdl_sub/script/types/variable_dependency.py b/src/ytdl_sub/script/types/variable_dependency.py index f6d3a47a..75a0383f 100644 --- a/src/ytdl_sub/script/types/variable_dependency.py +++ b/src/ytdl_sub/script/types/variable_dependency.py @@ -2,6 +2,7 @@ from abc import ABC from abc import abstractmethod from dataclasses import dataclass from typing import Dict +from typing import Iterable from typing import List from typing import Set from typing import final @@ -94,10 +95,14 @@ class VariableDependency(ABC): raise UNREACHABLE @final - def has_variable_dependency(self, resolved_variables: Dict[Variable, Resolvable]) -> bool: + def is_subset_of(self, variables: Iterable[Variable]) -> bool: """ Returns ------- 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 diff --git a/tests/unit/script/test_script.py b/tests/unit/script/test_script.py index 44cf164b..a89524b2 100644 --- a/tests/unit/script/test_script.py +++ b/tests/unit/script/test_script.py @@ -26,7 +26,7 @@ class TestScript: "bb": "b", "cc": "{%custom_func(aa, bb)}", } - ).partial_resolve(unresolvable={"bb"}) == {"aa": String("a")} + ).resolve(unresolvable={"bb"}) == {"aa": String("a")} def test_partial_update_script(self): script = Script( @@ -37,7 +37,7 @@ class TestScript: } ) - overrides = script.partial_resolve(unresolvable={"entry"}) + overrides = script.resolve(unresolvable={"entry"}) assert overrides == {"override": String("hi")} entry_map = ResolvedMap({String("title"): String("the title")})