From c0e2ded1ae11bafe42d361c93324903bb212761d Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Tue, 19 Dec 2023 00:22:14 -0800 Subject: [PATCH] [BACKEND] Improved error messages when script resolution does not work (#846) --- src/ytdl_sub/config/overrides.py | 29 ++++++++++++++++++++++------- src/ytdl_sub/script/script.py | 8 +++++++- src/ytdl_sub/utils/scriptable.py | 21 ++++++++++++++++++--- 3 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/ytdl_sub/config/overrides.py b/src/ytdl_sub/config/overrides.py index 340413f6..8f6903d2 100644 --- a/src/ytdl_sub/config/overrides.py +++ b/src/ytdl_sub/config/overrides.py @@ -11,7 +11,9 @@ from ytdl_sub.entries.variables.override_variables import SUBSCRIPTION_NAME from ytdl_sub.entries.variables.override_variables import OverrideVariables from ytdl_sub.script.parser import parse from ytdl_sub.script.script import Script +from ytdl_sub.script.utils.exceptions import ScriptVariableNotResolved from ytdl_sub.utils.exceptions import InvalidVariableNameException +from ytdl_sub.utils.exceptions import StringFormattingException from ytdl_sub.utils.exceptions import ValidationException from ytdl_sub.utils.script import ScriptUtils from ytdl_sub.utils.scriptable import Scriptable @@ -170,6 +172,11 @@ class Overrides(DictFormatterValidator, Scriptable): Returns ------- The format_string after .format has been called + + Raises + ------ + StringFormattingException + If the formatter that is trying to be resolved cannot """ script: Script = self.script unresolvable: Set[str] = self.unresolvable @@ -177,11 +184,19 @@ class Overrides(DictFormatterValidator, Scriptable): script = entry.script unresolvable = entry.unresolvable - return formatter.post_process( - str( - script.resolve_once( - dict({"tmp_var": formatter.format_string}, **(function_overrides or {})), - unresolvable=unresolvable, - )["tmp_var"] + try: + return formatter.post_process( + str( + script.resolve_once( + dict({"tmp_var": formatter.format_string}, **(function_overrides or {})), + unresolvable=unresolvable, + )["tmp_var"] + ) ) - ) + except ScriptVariableNotResolved as exc: + raise StringFormattingException( + "Tried to resolve the following script, but could not due to unresolved " + f"variables:\n {formatter.format_string}\n" + "This is most likely due to circular dependencies in variables. " + "If you think otherwise, please file a bug on GitHub and post your config. Thanks!" + ) from exc diff --git a/src/ytdl_sub/script/script.py b/src/ytdl_sub/script/script.py index 2747f003..0560984b 100644 --- a/src/ytdl_sub/script/script.py +++ b/src/ytdl_sub/script/script.py @@ -16,6 +16,7 @@ from ytdl_sub.script.utils.exceptions import CycleDetected from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments from ytdl_sub.script.utils.exceptions import InvalidCustomFunctionArguments from ytdl_sub.script.utils.exceptions import RuntimeException +from ytdl_sub.script.utils.exceptions import ScriptVariableNotResolved from ytdl_sub.script.utils.name_validation import validate_variable_name from ytdl_sub.script.utils.type_checking import FunctionSpec @@ -269,6 +270,11 @@ class Script: Returns ------- Dict of resolved values + + Raises + ------ + ScriptVariableNotResolved + If specifying a filter of variable to resolve, and one of them does not. """ resolved: Dict[Variable, Resolvable] = { Variable(name): value for name, value in (pre_resolved or {}).items() @@ -322,7 +328,7 @@ class Script: if output_filter: for name in output_filter: if name not in resolved_variables: - raise ValueError(f"Specified {name} to resolve, but it did not") + raise ScriptVariableNotResolved(f"Specified {name} to resolve, but it did not") return ScriptOutput( { diff --git a/src/ytdl_sub/utils/scriptable.py b/src/ytdl_sub/utils/scriptable.py index 8c136023..0dace721 100644 --- a/src/ytdl_sub/utils/scriptable.py +++ b/src/ytdl_sub/utils/scriptable.py @@ -9,6 +9,8 @@ from ytdl_sub.entries.script.variable_definitions import Variable from ytdl_sub.entries.script.variable_scripts import UNRESOLVED_VARIABLES from ytdl_sub.entries.script.variable_scripts import VARIABLE_SCRIPTS from ytdl_sub.script.script import Script +from ytdl_sub.script.utils.exceptions import RuntimeException +from ytdl_sub.utils.exceptions import StringFormattingException from ytdl_sub.utils.script import ScriptUtils @@ -37,15 +39,28 @@ class Scriptable(ABC): Add new values to the script """ values_as_str: Dict[str, str] = { - (key.variable_name if isinstance(key, Variable) else key): val - for key, val in values.items() + (var.variable_name if isinstance(var, Variable) else var): definition + for var, definition in values.items() } self.unresolvable -= set(list(values_as_str.keys())) self.script.add( ScriptUtils.add_sanitized_variables( - {name: ScriptUtils.to_script(value) for name, value in values_as_str.items()} + { + name: ScriptUtils.to_script(definition) + for name, definition in values_as_str.items() + } ), unresolvable=self.unresolvable, ) self.update_script() + + for name, definition in values_as_str.items(): + try: + _ = self.script.get(variable_name=name) + except RuntimeException as exc: + raise StringFormattingException( + f"Tried to create the variable with name {name} and definition:\n" + f"{definition}\n" + f"But could not because it has variable dependencies that are not resolved yet" + ) from exc