green and fast, try to not parse twice

This commit is contained in:
Jesse Bannon 2025-12-30 00:04:15 -08:00
parent 779ffbdf9a
commit 6302ec417d
2 changed files with 10 additions and 118 deletions

View file

@ -1,10 +1,4 @@
import copy
from typing import Dict from typing import Dict
from typing import Iterable
from typing import List
from typing import Optional
from typing import Set
from typing import Tuple
from ytdl_sub.config.overrides import Overrides from ytdl_sub.config.overrides import Overrides
from ytdl_sub.config.plugin.plugin_mapping import PluginMapping from ytdl_sub.config.plugin.plugin_mapping import PluginMapping
@ -13,80 +7,8 @@ from ytdl_sub.config.plugin.preset_plugins import PresetPlugins
from ytdl_sub.config.preset_options import OutputOptions from ytdl_sub.config.preset_options import OutputOptions
from ytdl_sub.config.validators.options import OptionsValidator from ytdl_sub.config.validators.options import OptionsValidator
from ytdl_sub.downloaders.url.validators import MultiUrlValidator from ytdl_sub.downloaders.url.validators import MultiUrlValidator
from ytdl_sub.entries.variables.override_variables import REQUIRED_OVERRIDE_VARIABLE_NAMES
from ytdl_sub.script.script import Script
from ytdl_sub.script.utils.exceptions import RuntimeException
from ytdl_sub.utils.scriptable import BASE_SCRIPT
from ytdl_sub.validators.string_formatter_validators import to_variable_dependency_format_string
from ytdl_sub.validators.string_formatter_validators import validate_formatters from ytdl_sub.validators.string_formatter_validators import validate_formatters
# Entry variables to mock during validation
_DUMMY_ENTRY_VARIABLES: Dict[str, str] = {
name: to_variable_dependency_format_string(
# pylint: disable=protected-access
script=BASE_SCRIPT,
parsed_format_string=BASE_SCRIPT._variables[name],
# pylint: enable=protected-access
)
for name in BASE_SCRIPT.variable_names
}
def _add_dummy_variables(variables: Iterable[str]) -> Dict[str, str]:
dummy_variables: Dict[str, str] = {}
for var in variables:
dummy_variables[var] = ""
dummy_variables[f"{var}_sanitized"] = ""
return dummy_variables
def _add_dummy_overrides(overrides: Overrides) -> Dict[str, str]:
# Have the dummy override variable contain all variable deps that it uses in the string
dummy_overrides: Dict[str, str] = {}
for override_name in overrides.script.variable_names:
try:
# Attempt to get the resolved version, which will only happen
# if it does not have any dependencies to the entry
value = f'{{%string("""{overrides.script.get(override_name).native}""")}}'
except RuntimeException:
value = to_variable_dependency_format_string(
script=overrides.script,
parsed_format_string=overrides.script._variables[override_name],
)
dummy_overrides[override_name] = value
return dummy_overrides
def _get_added_and_modified_variables(
plugins: PresetPlugins, downloader_options: MultiUrlValidator, output_options: OutputOptions
) -> Iterable[Tuple[OptionsValidator, Set[str], Set[str]]]:
"""
Iterates and returns the plugin options, added variables, modified variables
"""
options: List[OptionsValidator] = plugins.plugin_options
options.append(downloader_options)
options.append(output_options)
for plugin_options in options:
added_variables: Set[str] = set()
modified_variables: Set[str] = set()
for plugin_added_variables in plugin_options.added_variables(
unresolved_variables=set(),
).values():
added_variables |= set(plugin_added_variables)
for plugin_modified_variables in plugin_options.modified_variables().values():
modified_variables = plugin_modified_variables
yield plugin_options, added_variables, modified_variables
def _override_variables(overrides: Overrides) -> Set[str]:
return set(list(overrides.initial_variables().keys()))
class VariableValidation: class VariableValidation:
def __init__( def __init__(
@ -101,44 +23,11 @@ class VariableValidation:
self.output_options = output_options self.output_options = output_options
self.plugins = plugins self.plugins = plugins
self.script: Optional[Script] = None self.script = self.overrides.script
self.resolved_variables: Set[str] = set() self.unresolved_variables = self.plugins.get_all_variables(
self.unresolved_variables: Set[str] = set()
self._initialize_mock_script()
def _initialize_mock_script(
self,
) -> "VariableValidation":
plugin_variables = self.plugins.get_all_variables(
additional_options=[self.output_options, self.downloader_options] additional_options=[self.output_options, self.downloader_options]
) )
self.unresolved_variables = plugin_variables
# Set resolved variables as all entry + override variables
# at this point to generate every possible added/modified variable
self.resolved_variables = (
set(_DUMMY_ENTRY_VARIABLES.keys())
| set(list(self.overrides.initial_variables().keys()))
) - self.unresolved_variables
# copy the script and mock entry variables
self.script = copy.deepcopy(self.overrides.script)
# self.script.add(
# variables=_DUMMY_ENTRY_VARIABLES
# | _add_dummy_variables(variables=plugin_variables)
# | _add_dummy_overrides(overrides=self.overrides)
# )
return self
def _add_subscription_override_variables(self) -> None:
"""
Add dummy subscription variables for script validation
"""
self.resolved_variables |= REQUIRED_OVERRIDE_VARIABLE_NAMES
def _add_variables(self, plugin_op: PluginOperation, options: OptionsValidator) -> None: def _add_variables(self, plugin_op: PluginOperation, options: OptionsValidator) -> None:
""" """
Add dummy variables for script validation Add dummy variables for script validation
@ -148,10 +37,7 @@ class VariableValidation:
).get(plugin_op, set()) ).get(plugin_op, set())
modified_variables = options.modified_variables().get(plugin_op, set()) modified_variables = options.modified_variables().get(plugin_op, set())
resolved_variables = added_variables | modified_variables self.unresolved_variables -= added_variables | modified_variables
self.resolved_variables |= resolved_variables
self.unresolved_variables -= resolved_variables
def ensure_proper_usage(self) -> Dict: def ensure_proper_usage(self) -> Dict:
""" """
@ -162,7 +48,6 @@ class VariableValidation:
resolved_subscription: Dict = {} resolved_subscription: Dict = {}
self._add_variables(PluginOperation.DOWNLOADER, options=self.downloader_options) self._add_variables(PluginOperation.DOWNLOADER, options=self.downloader_options)
self._add_subscription_override_variables()
# Always add output options first # Always add output options first
self._add_variables(PluginOperation.MODIFY_ENTRY_METADATA, options=self.output_options) self._add_variables(PluginOperation.MODIFY_ENTRY_METADATA, options=self.output_options)

View file

@ -72,6 +72,11 @@ class StringFormatterValidator(StringValidator):
@property @property
@final @final
def parsed(self) -> SyntaxTree: def parsed(self) -> SyntaxTree:
"""
Returns
-------
The parsed format string.
"""
return self._parsed return self._parsed
def post_process(self, resolved: str) -> str: def post_process(self, resolved: str) -> str:
@ -318,6 +323,8 @@ def validate_formatters(
formatter_validator=validator_value, formatter_validator=validator_value,
) )
else: else:
# pylint: disable=protected-access
resolved_dict[validator.leaf_name] = validator._value resolved_dict[validator.leaf_name] = validator._value
# pylint: enable=protected-access
return resolved_dict return resolved_dict