diff --git a/src/ytdl_sub/config/overrides.py b/src/ytdl_sub/config/overrides.py index 36fe785f..b012a658 100644 --- a/src/ytdl_sub/config/overrides.py +++ b/src/ytdl_sub/config/overrides.py @@ -2,6 +2,7 @@ import copy from typing import Any from typing import Dict from typing import Optional +from typing import Set from yt_dlp.utils import sanitize_filename @@ -9,6 +10,7 @@ from ytdl_sub.entries.entry import Entry from ytdl_sub.entries.script.variable_definitions import VARIABLES from ytdl_sub.entries.variables.override_variables import SUBSCRIPTION_NAME from ytdl_sub.script.parser import parse +from ytdl_sub.script.script import Script from ytdl_sub.utils.scriptable import Scriptable from ytdl_sub.validators.string_formatter_validators import DictFormatterValidator from ytdl_sub.validators.string_formatter_validators import StringFormatterValidator @@ -116,14 +118,15 @@ class Overrides(DictFormatterValidator, Scriptable): ------- The format_string after .format has been called """ + script: Script = self.script + unresolvable: Set[str] = self.unresolvable if entry: script = entry.script unresolvable = entry.unresolvable - else: - script = self.script - unresolvable = self.unresolvable - if function_overrides: - script = copy.deepcopy(script).add(function_overrides) - - return str(script.resolve_once(formatter.format_string, unresolvable=unresolvable)) + return str( + script.resolve_once( + dict({"tmp_var": formatter.format_string}, **(function_overrides or {})), + unresolvable=unresolvable, + )["tmp_var"] + ) diff --git a/src/ytdl_sub/config/preset.py b/src/ytdl_sub/config/preset.py index 92a8bb8d..29dead33 100644 --- a/src/ytdl_sub/config/preset.py +++ b/src/ytdl_sub/config/preset.py @@ -259,7 +259,7 @@ class Preset(_PresetShell): ) -> None: try: self._script.resolve_once( - formatter_validator.format_string, + {"tmp_var": formatter_validator.format_string}, unresolvable=self._get_unresolvable_variables(formatter_validator), ) except VariableDoesNotExist as exc: diff --git a/src/ytdl_sub/downloaders/url/validators.py b/src/ytdl_sub/downloaders/url/validators.py index 63f5b2b9..0185e300 100644 --- a/src/ytdl_sub/downloaders/url/validators.py +++ b/src/ytdl_sub/downloaders/url/validators.py @@ -259,13 +259,17 @@ class MultiUrlValidator(OptionsValidator): """ # Apply formatting to each new source variable, ensure it resolves for collection_url in self.urls.list: - for name, definition in collection_url.variables.dict_with_format_strings.items(): - script.resolve_once(variable_name=name, variable_definition=definition) + script.resolve_once(collection_url.variables.dict_with_format_strings) # Ensure at least URL is non-empty has_non_empty_url = False - for url_validator in self.urls.list: - has_non_empty_url |= bool(str(script.resolve_once(url_validator.url.format_string))) + url_variables = { + f"tmp_var_url_{idx}": url_validator.url.format_string + for idx, url_validator in enumerate(self.urls.list) + } + output = script.resolve_once(url_variables) + for out in output: + has_non_empty_url |= bool(str(out)) if not has_non_empty_url: raise self._validation_exception("Must contain at least one url that is non-empty") diff --git a/src/ytdl_sub/script/script.py b/src/ytdl_sub/script/script.py index 8a16ece1..db00effc 100644 --- a/src/ytdl_sub/script/script.py +++ b/src/ytdl_sub/script/script.py @@ -331,6 +331,10 @@ class Script: self._update_internally(resolved_variables=resolved_variables) 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") + return ScriptOutput( { name: resolvable @@ -369,20 +373,21 @@ class Script: def resolve_once( self, - variable_definition: str, - variable_name: Optional[str] = None, + variable_definitions: Dict[str, str], resolved: Optional[Dict[str, Resolvable]] = None, unresolvable: Optional[Set[str]] = None, - ) -> Resolvable: - var_name = variable_name if variable_name else "tmp_var" + ) -> Dict[str, Resolvable]: try: - self.add({var_name: variable_definition}) + self.add(variable_definitions) return self._resolve( - pre_resolved=resolved, unresolvable=unresolvable, output_filter={var_name} - ).get(var_name) + pre_resolved=resolved, + unresolvable=unresolvable, + output_filter=set(list(variable_definitions.keys())), + ).output finally: - if var_name in self._variables: - del self._variables[var_name] + for name in variable_definitions.keys(): + if name in self._variables: + del self._variables[name] def get(self, variable_name: str) -> Resolvable: if variable_name not in self._variables: diff --git a/tests/unit/prebuilt_presets/test_prebuilt_presets.py b/tests/unit/prebuilt_presets/test_prebuilt_presets.py index a892be63..1f0e6d7a 100644 --- a/tests/unit/prebuilt_presets/test_prebuilt_presets.py +++ b/tests/unit/prebuilt_presets/test_prebuilt_presets.py @@ -153,6 +153,9 @@ class TestPrebuiltTVShowPresets: is_youtube_channel: bool, is_many_urls: bool, ): + # yappi.set_clock_type("wall") # Use set_clock_type("wall") for wall time + # yappi.start() + expected_summary_name = "unit/{}/{}/is_yt_{}{}".format( media_player_preset, tv_show_structure_preset, @@ -180,9 +183,6 @@ class TestPrebuiltTVShowPresets: preset_dict=preset_dict, ) - # yappi.set_clock_type("wall") # Use set_clock_type("wall") for wall time - # yappi.start() - with mock_download_collection_entries( is_youtube_channel=is_youtube_channel, num_urls=2 if is_many_urls else 1 ):