[BACKEND] Disallow override names conflicting with plugin names (#1399)

Disallow override variable names conflicting with plugin names.

May cause backward incompatible issues from `date_range` being an old override variable name for the `Only Recent` preset. Update this variable name to `only_recent_date_range` to resolve. More info in https://ytdl-sub.readthedocs.io/en/latest/deprecation_notices.html
This commit is contained in:
Jesse Bannon 2025-12-26 15:30:37 -08:00 committed by GitHub
parent 157a0b59c4
commit 0f96d8e24e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 57 additions and 7 deletions

View file

@ -1,6 +1,15 @@
Deprecation Notices Deprecation Notices
=================== ===================
Dec 2025
--------
Override variables names can no longer be plugin names, to avoid the common pitfall of
defining a plugin underneath ``overrides``.
In the past, there was usage of a ``date_range`` override variable in a few example configs
that complimented the ``Only Recent`` preset. This overrride variable usage needs to be
replaced with ``only_recent_date_range``.
Sep 2024 Sep 2024
-------- --------

View file

@ -24,6 +24,6 @@ TV Show Only Recent:
# to set only for that subscriptions # to set only for that subscriptions
"~BBC News": "~BBC News":
url: "https://www.youtube.com/@BBCNews" # use url2, url3, ... for multi-url in this form url: "https://www.youtube.com/@BBCNews" # use url2, url3, ... for multi-url in this form
date_range: "2weeks" only_recent_date_range: "2weeks"
"Frontline PBS": "https://www.youtube.com/@frontline" "Frontline PBS": "https://www.youtube.com/@frontline"
"Whitehouse": "https://www.bitchute.com/channel/zWsYVmCOu4JA/" # Supports non-YT sites "Whitehouse": "https://www.bitchute.com/channel/zWsYVmCOu4JA/" # Supports non-YT sites

View file

@ -1,5 +1,6 @@
from typing import Any from typing import Any
from typing import Dict from typing import Dict
from typing import Iterable
from typing import Optional from typing import Optional
from typing import Set from typing import Set
@ -88,6 +89,24 @@ class Overrides(UnstructuredDictFormatterValidator, Scriptable):
return True return True
def ensure_variable_names_not_a_plugin(self, plugin_names: Iterable[str]) -> None:
"""
Throws an error if an override variable or function has the same name as a
preset key. This is to avoid confusion when accidentally defining things in
overrides that are meant to be in the preset.
"""
for name in self.keys:
if name.startswith("%"):
name = name[1:]
if name in plugin_names:
raise self._validation_exception(
f"Override variable with name {name} cannot be used since it is"
" the name of a plugin. Perhaps you meant to define it as a plugin? If so,"
" indent it left to make it at the same level as overrides.",
exception_class=InvalidVariableNameException,
)
def ensure_variable_name_valid(self, name: str) -> None: def ensure_variable_name_valid(self, name: str) -> None:
""" """
Ensures the variable name does not collide with any entry variables or built-in functions. Ensures the variable name does not collide with any entry variables or built-in functions.

View file

@ -194,6 +194,8 @@ class Preset(_PresetShell):
self.plugins: PresetPlugins = self._validate_and_get_plugins() self.plugins: PresetPlugins = self._validate_and_get_plugins()
self.overrides = self._validate_key(key="overrides", validator=Overrides, default={}) self.overrides = self._validate_key(key="overrides", validator=Overrides, default={})
self.overrides.ensure_variable_names_not_a_plugin(plugin_names=PRESET_KEYS)
VariableValidation( VariableValidation(
downloader_options=self.downloader_options, downloader_options=self.downloader_options,
output_options=self.output_options, output_options=self.output_options,

View file

@ -11,9 +11,6 @@ from ytdl_sub.entries.script.variable_types import Variable
from ytdl_sub.script.functions import Functions from ytdl_sub.script.functions import Functions
from ytdl_sub.script.utils.name_validation import is_valid_name from ytdl_sub.script.utils.name_validation import is_valid_name
# TODO: use this
SUBSCRIPTION_ARRAY = "subscription_array"
class SubscriptionVariables: class SubscriptionVariables:
@staticmethod @staticmethod
@ -163,7 +160,7 @@ class OverrideHelpers:
True if the override name itself is valid. False otherwise. True if the override name itself is valid. False otherwise.
""" """
if name.startswith("%"): if name.startswith("%"):
return is_valid_name(name=name[1:]) name = name[1:]
return is_valid_name(name=name) return is_valid_name(name=name)

View file

@ -11,8 +11,7 @@ presets:
# Set the default date_range to 2 months # Set the default date_range to 2 months
overrides: overrides:
date_range: "2months" # keep for legacy-reasons only_recent_date_range: "2months"
only_recent_date_range: "{date_range}"
############################################################################# #############################################################################
# Only Recent # Only Recent

View file

@ -435,3 +435,27 @@ class TestPreset:
"output_options": {"output_directory": "dir", "file_name": "acjk"}, "output_options": {"output_directory": "dir", "file_name": "acjk"},
}, },
) )
def test_preset_error_override_name_conflicts_with_plugin(self, config_file, output_options):
with pytest.raises(
ValidationException,
match=re.escape(
"Override variable with name throttle_protection cannot be used since it is the "
"name of a plugin. Perhaps you meant to define it as a plugin? If so, indent it "
"left to make it at the same level as overrides."
),
):
_ = Preset(
config=config_file,
name="test",
value={
"download": {
"url": "youtube.com/watch?v=123abc",
},
"subtitles": {
"embed_subtitles": True,
},
"output_options": {"output_directory": "dir", "file_name": "acjk"},
"overrides": {"throttle_protection": "nope"},
},
)