From 0f96d8e24e6523894ac6953a5fde669a007917dd Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Fri, 26 Dec 2025 15:30:37 -0800 Subject: [PATCH] [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 --- docs/source/deprecation_notices.rst | 9 +++++++ examples/advanced/tv_show_subscriptions.yaml | 2 +- src/ytdl_sub/config/overrides.py | 19 +++++++++++++++ src/ytdl_sub/config/preset.py | 2 ++ .../entries/variables/override_variables.py | 5 +--- .../helpers/download_deletion_options.yaml | 3 +-- tests/unit/config/test_preset.py | 24 +++++++++++++++++++ 7 files changed, 57 insertions(+), 7 deletions(-) diff --git a/docs/source/deprecation_notices.rst b/docs/source/deprecation_notices.rst index 9fc4b48d..a75240c2 100644 --- a/docs/source/deprecation_notices.rst +++ b/docs/source/deprecation_notices.rst @@ -1,6 +1,15 @@ 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 -------- diff --git a/examples/advanced/tv_show_subscriptions.yaml b/examples/advanced/tv_show_subscriptions.yaml index 52e1728c..f0b18dfa 100644 --- a/examples/advanced/tv_show_subscriptions.yaml +++ b/examples/advanced/tv_show_subscriptions.yaml @@ -24,6 +24,6 @@ TV Show Only Recent: # to set only for that subscriptions "~BBC News": 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" "Whitehouse": "https://www.bitchute.com/channel/zWsYVmCOu4JA/" # Supports non-YT sites \ No newline at end of file diff --git a/src/ytdl_sub/config/overrides.py b/src/ytdl_sub/config/overrides.py index 06ca8fce..c3b791b7 100644 --- a/src/ytdl_sub/config/overrides.py +++ b/src/ytdl_sub/config/overrides.py @@ -1,5 +1,6 @@ from typing import Any from typing import Dict +from typing import Iterable from typing import Optional from typing import Set @@ -88,6 +89,24 @@ class Overrides(UnstructuredDictFormatterValidator, Scriptable): 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: """ Ensures the variable name does not collide with any entry variables or built-in functions. diff --git a/src/ytdl_sub/config/preset.py b/src/ytdl_sub/config/preset.py index 914ebc77..31ac34a8 100644 --- a/src/ytdl_sub/config/preset.py +++ b/src/ytdl_sub/config/preset.py @@ -194,6 +194,8 @@ class Preset(_PresetShell): self.plugins: PresetPlugins = self._validate_and_get_plugins() self.overrides = self._validate_key(key="overrides", validator=Overrides, default={}) + self.overrides.ensure_variable_names_not_a_plugin(plugin_names=PRESET_KEYS) + VariableValidation( downloader_options=self.downloader_options, output_options=self.output_options, diff --git a/src/ytdl_sub/entries/variables/override_variables.py b/src/ytdl_sub/entries/variables/override_variables.py index e9b3da07..8dd2081c 100644 --- a/src/ytdl_sub/entries/variables/override_variables.py +++ b/src/ytdl_sub/entries/variables/override_variables.py @@ -11,9 +11,6 @@ from ytdl_sub.entries.script.variable_types import Variable from ytdl_sub.script.functions import Functions from ytdl_sub.script.utils.name_validation import is_valid_name -# TODO: use this -SUBSCRIPTION_ARRAY = "subscription_array" - class SubscriptionVariables: @staticmethod @@ -163,7 +160,7 @@ class OverrideHelpers: True if the override name itself is valid. False otherwise. """ if name.startswith("%"): - return is_valid_name(name=name[1:]) + name = name[1:] return is_valid_name(name=name) diff --git a/src/ytdl_sub/prebuilt_presets/helpers/download_deletion_options.yaml b/src/ytdl_sub/prebuilt_presets/helpers/download_deletion_options.yaml index 676862a3..0bf420c3 100644 --- a/src/ytdl_sub/prebuilt_presets/helpers/download_deletion_options.yaml +++ b/src/ytdl_sub/prebuilt_presets/helpers/download_deletion_options.yaml @@ -11,8 +11,7 @@ presets: # Set the default date_range to 2 months overrides: - date_range: "2months" # keep for legacy-reasons - only_recent_date_range: "{date_range}" + only_recent_date_range: "2months" ############################################################################# # Only Recent diff --git a/tests/unit/config/test_preset.py b/tests/unit/config/test_preset.py index 939eab92..8e9b4c89 100644 --- a/tests/unit/config/test_preset.py +++ b/tests/unit/config/test_preset.py @@ -435,3 +435,27 @@ class TestPreset: "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"}, + }, + )