This commit is contained in:
Jesse Bannon 2025-12-31 08:09:28 -08:00
parent f4c8405dc2
commit f50b49d1c5
4 changed files with 32 additions and 4 deletions

View file

@ -71,16 +71,17 @@ class Script:
): ):
for dep in self._functions[custom_func.name].variables: for dep in self._functions[custom_func.name].variables:
self._ensure_no_cycle( self._ensure_no_cycle(
name=variable_name, dep=dep.name, deps=deps, definitions=self._variables name=variable_name,
dep=dep.name,
deps=deps + [custom_func.definition_name()],
definitions=self._variables,
) )
self._traverse_variable_dependencies( self._traverse_variable_dependencies(
variable_name=variable_name, variable_name=variable_name,
variable_dependency=self._variables[dep.name], variable_dependency=self._variables[dep.name],
deps=deps + [dep.name], deps=deps + [custom_func.definition_name(), dep.name],
) )
def _ensure_no_variable_cycles(self, variables: Dict[str, SyntaxTree]): def _ensure_no_variable_cycles(self, variables: Dict[str, SyntaxTree]):
for variable_name, variable_definition in variables.items(): for variable_name, variable_definition in variables.items():
self._traverse_variable_dependencies( self._traverse_variable_dependencies(

View file

@ -193,6 +193,14 @@ class NamedCustomFunction(NamedArgument, ABC):
class ParsedCustomFunction(NamedCustomFunction): class ParsedCustomFunction(NamedCustomFunction):
num_input_args: int num_input_args: int
def definition_name(self) -> str:
"""
Returns
-------
The function definition name, including the %
"""
return f"%{self.name}"
@dataclass(frozen=True) @dataclass(frozen=True)
class FunctionType(NamedArgument, ABC): class FunctionType(NamedArgument, ABC):

View file

@ -163,6 +163,17 @@ class VariableDependency(ABC):
def custom_function_dependencies( def custom_function_dependencies(
self, custom_function_definitions: Dict[str, "VariableDependency"] self, custom_function_definitions: Dict[str, "VariableDependency"]
) -> Set[ParsedCustomFunction]: ) -> Set[ParsedCustomFunction]:
"""
Parameters
----------
custom_function_definitions
Definition of all currently existing custom functions. Needed to check whether
a lambda function's input function is custom or not.
Returns
-------
All custom function dependencies
"""
custom_functions = self.custom_functions custom_functions = self.custom_functions
for lambda_func in self.lambdas: for lambda_func in self.lambdas:
if lambda_func.value in custom_function_definitions: if lambda_func.value in custom_function_definitions:

View file

@ -6,6 +6,7 @@ from ytdl_sub.script.script import Script
from ytdl_sub.script.script_output import ScriptOutput from ytdl_sub.script.script_output import ScriptOutput
from ytdl_sub.script.types.array import Array from ytdl_sub.script.types.array import Array
from ytdl_sub.script.types.resolvable import Integer from ytdl_sub.script.types.resolvable import Integer
from ytdl_sub.script.utils.exceptions import CycleDetected
from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments
@ -169,3 +170,10 @@ class TestLambdaFunctionIncompatibleNumArguments:
"%output": f"{{%array_enumerate(array1, {lambda_value})}}", "%output": f"{{%array_enumerate(array1, {lambda_value})}}",
} }
) )
def test_lambda_with_custom_function_cycle(self):
with pytest.raises(
CycleDetected,
match=re.escape("Cycle detected within these variables: two -> %times_two -> two"),
):
Script({"%times_two": "{%mul($0, two)}", "two": "{%times_two(2)}"})