This commit is contained in:
Jesse Bannon 2025-12-27 12:02:49 -08:00
parent a6702dc723
commit 4b7d6ae12b
7 changed files with 39 additions and 36 deletions

1
.gitignore vendored
View file

@ -146,6 +146,7 @@ docker/testing/volumes
.local/ .local/
.ytdl-sub-working-directory .ytdl-sub-working-directory
.ytdl-sub-lock
ffmpeg.exe ffmpeg.exe
ffprobe.exe ffprobe.exe

View file

@ -220,6 +220,9 @@ class PluginMapping:
@classmethod @classmethod
def name_of(cls, plugin_options: OptionsValidator) -> str: def name_of(cls, plugin_options: OptionsValidator) -> str:
"""
Returns plugin definition's name.
"""
for name, plugin_type in cls._MAPPING.items(): for name, plugin_type in cls._MAPPING.items():
if plugin_type.plugin_options_type == plugin_options.__class__: if plugin_type.plugin_options_type == plugin_options.__class__:
return name return name

View file

@ -68,6 +68,9 @@ class PresetPlugins:
yield plugin_options, added_variables, modified_variables yield plugin_options, added_variables, modified_variables
def get_all_variables(self, additional_options: List[OptionsValidator]) -> Set[str]: def get_all_variables(self, additional_options: List[OptionsValidator]) -> Set[str]:
"""
Returns set of all added and modified variables' names.
"""
all_variables: Set[str] = set() all_variables: Set[str] = set()
for _, added, modified in self.get_added_and_modified_variables(additional_options): for _, added, modified in self.get_added_and_modified_variables(additional_options):
all_variables.update(added) all_variables.update(added)

View file

@ -88,10 +88,12 @@ def _override_variables(overrides: Overrides) -> Set[str]:
class VariableValidation: class VariableValidation:
def __init__( def __init__(
self, self,
overrides: Overrides,
downloader_options: MultiUrlValidator, downloader_options: MultiUrlValidator,
output_options: OutputOptions, output_options: OutputOptions,
plugins: PresetPlugins, plugins: PresetPlugins,
): ):
self.overrides = overrides
self.downloader_options = downloader_options self.downloader_options = downloader_options
self.output_options = output_options self.output_options = output_options
self.plugins = plugins self.plugins = plugins
@ -100,9 +102,10 @@ class VariableValidation:
self.resolved_variables: Set[str] = set() self.resolved_variables: Set[str] = set()
self.unresolved_variables: Set[str] = set() self.unresolved_variables: Set[str] = set()
def initialize_preset_overrides( self._initialize_mock_script()
def _initialize_mock_script(
self, self,
overrides: Overrides,
) -> "VariableValidation": ) -> "VariableValidation":
plugin_variables = self.plugins.get_all_variables( plugin_variables = self.plugins.get_all_variables(
additional_options=[self.output_options, self.downloader_options] additional_options=[self.output_options, self.downloader_options]
@ -113,13 +116,14 @@ class VariableValidation:
# Set resolved variables as all entry + override variables # Set resolved variables as all entry + override variables
# at this point to generate every possible added/modified variable # at this point to generate every possible added/modified variable
self.resolved_variables = ( self.resolved_variables = (
set(_DUMMY_ENTRY_VARIABLES.keys()) | set(list(overrides.initial_variables().keys())) set(_DUMMY_ENTRY_VARIABLES.keys())
| set(list(self.overrides.initial_variables().keys()))
) - self.unresolved_variables ) - self.unresolved_variables
# copy the script and mock entry variables # copy the script and mock entry variables
self.script = copy.deepcopy(overrides.script) self.script = copy.deepcopy(self.overrides.script)
self.script.add( self.script.add(
variables=_add_dummy_overrides(overrides=overrides) variables=_add_dummy_overrides(overrides=self.overrides)
| _add_dummy_variables(variables=plugin_variables) | _add_dummy_variables(variables=plugin_variables)
| _DUMMY_ENTRY_VARIABLES | _DUMMY_ENTRY_VARIABLES
) )

View file

@ -103,15 +103,12 @@ class BaseSubscription(ABC):
f"{self.output_directory}" f"{self.output_directory}"
) )
self._validated_dict = ( self._validated_dict = VariableValidation(
VariableValidation( overrides=self.overrides,
downloader_options=self.downloader_options, downloader_options=self.downloader_options,
output_options=self.output_options, output_options=self.output_options,
plugins=self.plugins, plugins=self.plugins,
) ).ensure_proper_usage()
.initialize_preset_overrides(overrides=self.overrides)
.ensure_proper_usage()
)
@property @property
def download_archive(self) -> EnhancedDownloadArchive: def download_archive(self) -> EnhancedDownloadArchive:
@ -258,4 +255,9 @@ class BaseSubscription(ABC):
return self._preset_options.yaml return self._preset_options.yaml
def resolved_yaml(self): def resolved_yaml(self):
"""
Returns
-------
Human-readable, condensed YAML definition of the subscription.
"""
return self._validated_dict return self._validated_dict

View file

@ -268,21 +268,21 @@ def validate_formatters(
""" """
resolved_dict: Dict = {} resolved_dict: Dict = {}
if isinstance(validator, DictValidator): if isinstance(validator, DictValidator):
resolved_dict[validator._leaf_name] = {} resolved_dict[validator.leaf_name] = {}
# pylint: disable=protected-access # pylint: disable=protected-access
# Usage of protected variables in other validators is fine. The reason to keep # Usage of protected variables in other validators is fine. The reason to keep
# them protected is for readability when using them in subscriptions. # them protected is for readability when using them in subscriptions.
for validator_value in validator._validator_dict.values(): for validator_value in validator._validator_dict.values():
resolved_dict[validator._leaf_name] |= validate_formatters( resolved_dict[validator.leaf_name] |= validate_formatters(
script=script, script=script,
unresolved_variables=unresolved_variables, unresolved_variables=unresolved_variables,
validator=validator_value, validator=validator_value,
) )
# pylint: enable=protected-access # pylint: enable=protected-access
elif isinstance(validator, ListValidator): elif isinstance(validator, ListValidator):
resolved_dict[validator._leaf_name] = [] resolved_dict[validator.leaf_name] = []
for list_value in validator.list: for list_value in validator.list:
resolved_dict[validator._leaf_name].append( resolved_dict[validator.leaf_name].append(
validate_formatters( validate_formatters(
script=script, script=script,
unresolved_variables=unresolved_variables, unresolved_variables=unresolved_variables,
@ -290,20 +290,20 @@ def validate_formatters(
) )
) )
elif isinstance(validator, (StringFormatterValidator, OverridesStringFormatterValidator)): elif isinstance(validator, (StringFormatterValidator, OverridesStringFormatterValidator)):
resolved_dict[validator._leaf_name] = _validate_formatter( resolved_dict[validator.leaf_name] = _validate_formatter(
mock_script=script, mock_script=script,
unresolved_variables=unresolved_variables, unresolved_variables=unresolved_variables,
formatter_validator=validator, formatter_validator=validator,
) )
elif isinstance(validator, (DictFormatterValidator, OverridesDictFormatterValidator)): elif isinstance(validator, (DictFormatterValidator, OverridesDictFormatterValidator)):
resolved_dict[validator._leaf_name] = {} resolved_dict[validator.leaf_name] = {}
for key, validator_value in validator.dict.items(): for validator_value in validator.dict.values():
resolved_dict[validator._leaf_name] |= _validate_formatter( resolved_dict[validator.leaf_name] |= _validate_formatter(
mock_script=script, mock_script=script,
unresolved_variables=unresolved_variables, unresolved_variables=unresolved_variables,
formatter_validator=validator_value, formatter_validator=validator_value,
) )
else: else:
resolved_dict[validator._leaf_name] = validator._value resolved_dict[validator.leaf_name] = validator._value
return resolved_dict return resolved_dict

View file

@ -95,21 +95,11 @@ class Validator(ABC):
@final @final
@property @property
def _root_name(self) -> str: def leaf_name(self) -> str:
""" """
Returns Returns
------- -------
"first" from the first.element.of.the.name "name" from the first.element.of.the.name
"""
return self._name.split(".")[0]
@final
@property
def _leaf_name(self) -> str:
"""
Returns
-------
"first" from the first.element.of.the.name
""" """
return self._name.split(".")[-1] return self._name.split(".")[-1]