From 219c0204dd0d006d51ebc6fac6b033515343fc46 Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Fri, 23 Jan 2026 00:02:52 -0800 Subject: [PATCH] do not resolve sanitizied using filter --- .../config/validators/variable_validation.py | 20 +++++++++++++++++-- src/ytdl_sub/script/script.py | 10 +++++----- .../script/types/variable_dependency.py | 2 ++ 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/ytdl_sub/config/validators/variable_validation.py b/src/ytdl_sub/config/validators/variable_validation.py index 74ed78fe..9293886c 100644 --- a/src/ytdl_sub/config/validators/variable_validation.py +++ b/src/ytdl_sub/config/validators/variable_validation.py @@ -1,5 +1,6 @@ from typing import Dict from typing import List +from typing import Set from ytdl_sub.config.overrides import Overrides from ytdl_sub.config.plugin.plugin_mapping import PluginMapping @@ -36,14 +37,29 @@ class ResolutionLevel: class VariableValidation: + def _get_resolve_partial_filter(self) -> Set[str]: + # Exclude sanitized variables from partial validation. This lessens the work + # and prevents double-evaluation, which can lead to bad behavior like double-prints. + return { + name + for name in self.script.variable_names + if name not in self.unresolved_variables and not name.endswith("_sanitized") + } + def _apply_resolution_level(self) -> None: if self._resolution_level == ResolutionLevel.RESOLVE: # Partial resolve everything, but not including internal variables self.unresolved_variables |= VARIABLES.variable_names(include_sanitized=True) - self.script = self.script.resolve_partial(unresolvable=self.unresolved_variables) + self.script = self.script.resolve_partial( + unresolvable=self.unresolved_variables, + output_filter=self._get_resolve_partial_filter(), + ) elif self._resolution_level == ResolutionLevel.INTERNAL: # Partial resolve everything including internal variables - self.script = self.script.resolve_partial(unresolvable=self.unresolved_variables) + self.script = self.script.resolve_partial( + unresolvable=self.unresolved_variables, + output_filter=self._get_resolve_partial_filter(), + ) else: raise ValueError("Invalid resolution level for validation") diff --git a/src/ytdl_sub/script/script.py b/src/ytdl_sub/script/script.py index cb4c5665..b008e2e5 100644 --- a/src/ytdl_sub/script/script.py +++ b/src/ytdl_sub/script/script.py @@ -742,11 +742,10 @@ class Script: if isinstance(definition, Variable) and definition.name not in unresolvable: if definition in resolved: maybe_resolved = resolved[definition] + elif definition in unresolved: + maybe_resolved = unresolved[definition] else: - # If it's not in resolved, it must be in unresolved. - # Do not modify the definition, this avoids duplicate work because it will - # wait for the single dependent variable to be resolved. - assert definition in unresolved + raise UNREACHABLE elif isinstance(definition, VariableDependency): maybe_resolved = definition.partial_resolve( resolved_variables=resolved, @@ -784,8 +783,9 @@ class Script: def resolve_partial( self, unresolvable: Optional[Set[str]] = None, + output_filter: Optional[Set[str]] = None, ) -> "Script": - out = self._resolve_partial(unresolvable=unresolvable) + out = self._resolve_partial(unresolvable=unresolvable, output_filter=output_filter) for var_name, definition in out.items(): self._variables[var_name] = definition diff --git a/src/ytdl_sub/script/types/variable_dependency.py b/src/ytdl_sub/script/types/variable_dependency.py index ad5d73c9..5cfee863 100644 --- a/src/ytdl_sub/script/types/variable_dependency.py +++ b/src/ytdl_sub/script/types/variable_dependency.py @@ -281,5 +281,7 @@ class VariableDependency(ABC): elif isinstance(arg, Variable): if arg not in resolved_variables: is_resolvable = False + if arg in unresolved_variables: + maybe_resolvable_args[-1] = unresolved_variables[arg] return maybe_resolvable_args, is_resolvable