match filter unit test

This commit is contained in:
Jesse Bannon 2025-06-01 07:17:13 -07:00
parent b8dd8bea5f
commit 6881b7ecf5
9 changed files with 148 additions and 49 deletions

View file

@ -1,5 +1,6 @@
from typing import List, Set from typing import List
from typing import Optional from typing import Optional
from typing import Set
from typing import Tuple from typing import Tuple
from ytdl_sub.config.plugin.plugin import Plugin from ytdl_sub.config.plugin.plugin import Plugin
@ -35,9 +36,11 @@ class DateRangeOptions(ToggleableOptionsDictValidator):
date_range: date_range:
before: "now" before: "now"
after: "today-2weeks" after: "today-2weeks"
breaks: True
type: "upload_date"
""" """
_optional_keys = {"enable", "before", "after", "breaks"} _optional_keys = {"enable", "before", "after", "breaks", "type"}
def __init__(self, name, value): def __init__(self, name, value):
super().__init__(name, value) super().__init__(name, value)
@ -81,7 +84,8 @@ class DateRangeOptions(ToggleableOptionsDictValidator):
""" """
:expected type: Optional[OverridesFormatter] :expected type: Optional[OverridesFormatter]
:description: :description:
Which type of date to use. Must be either ``upload_date`` or ``release_date`` Which type of date to use. Must be either ``upload_date`` or ``release_date``.
Defaults to ``upload_date``.
""" """
return self._type return self._type

View file

@ -349,12 +349,16 @@ class SubscriptionDownload(BaseSubscription, ABC):
return self.download_archive.get_file_handler_transaction_log() return self.download_archive.get_file_handler_transaction_log()
def get_ytdl_options(self, plugins: Optional[List[Plugin]], dry_run: bool) -> SubscriptionYTDLOptions: def get_ytdl_options(
self, plugins: Optional[List[Plugin]], dry_run: bool
) -> SubscriptionYTDLOptions:
""" """
Parameters Parameters
---------- ----------
plugins plugins
Optional. If not provided, will reinitialize them Optional. If not provided, will reinitialize them
dry_run
Whether its dry run or not
Returns Returns
------- -------
@ -392,10 +396,7 @@ class SubscriptionDownload(BaseSubscription, ABC):
logging.info("Skipping %s", self.name) logging.info("Skipping %s", self.name)
return FileHandlerTransactionLog() return FileHandlerTransactionLog()
subscription_ytdl_options = self.get_ytdl_options( subscription_ytdl_options = self.get_ytdl_options(plugins=plugins, dry_run=dry_run)
plugins=plugins,
dry_run=dry_run
)
downloader = MultiUrlDownloader( downloader = MultiUrlDownloader(
options=self.downloader_options, options=self.downloader_options,
@ -440,10 +441,7 @@ class SubscriptionDownload(BaseSubscription, ABC):
self.download_archive.reinitialize(dry_run=dry_run) self.download_archive.reinitialize(dry_run=dry_run)
plugins = self._initialize_plugins() plugins = self._initialize_plugins()
subscription_ytdl_options = self.get_ytdl_options( subscription_ytdl_options = self.get_ytdl_options(plugins=plugins, dry_run=dry_run)
plugins=plugins,
dry_run=dry_run
)
# Re-add the original downloader class' plugins # Re-add the original downloader class' plugins
plugins.extend( plugins.extend(

View file

@ -28,7 +28,7 @@ class OverridesStringSelectValidator(OverridesStringFormatterValidator):
def post_process(self, resolved: str) -> str: def post_process(self, resolved: str) -> str:
if resolved not in self._select_values: if resolved not in self._select_values:
raise self._validation_exception( raise self._validation_exception(
f"Must be one of the following values: {', '.join(self._select_values)}" f"Must be one of the following values: {', '.join(sorted(self._select_values))}"
) )
return resolved return resolved

View file

@ -12,6 +12,7 @@ from typing import Callable
from typing import Dict from typing import Dict
from typing import List from typing import List
from typing import Optional from typing import Optional
from typing import Tuple
from unittest.mock import patch from unittest.mock import patch
import pytest import pytest
@ -272,3 +273,27 @@ def mock_run_from_cli(args: str) -> List[Subscription]:
args_list = ["ytdl-sub"] + shlex.split(args) args_list = ["ytdl-sub"] + shlex.split(args)
with patch.object(sys, "argv", args_list): with patch.object(sys, "argv", args_list):
return main() return main()
def get_match_filters(
subscription: Subscription, dry_run: bool, download_filters: bool
) -> Tuple[List[str], List[str]]:
"""
Util function to get match filters from a subscription.
Returns
-------
match_filters, breaking_match_filters
"""
options = subscription.get_ytdl_options(plugins=None, dry_run=dry_run)
options_dict = (
options.download_builder().to_dict()
if download_filters
else options.metadata_builder().to_dict()
)
if "match_filter" not in options_dict:
return [], []
match_filter_str = repr(options_dict["match_filter"])
out = eval(match_filter_str.split("(", maxsplit=1)[-1].split(")")[0])
return out

View file

@ -1,6 +1,5 @@
import contextlib import contextlib
import os import os
import shutil
from pathlib import Path from pathlib import Path
from typing import Callable from typing import Callable
from typing import Dict from typing import Dict

View file

@ -1,34 +0,0 @@
import re
import pytest
from ytdl_sub.subscriptions.subscription import Subscription
from ytdl_sub.utils.exceptions import ValidationException
@pytest.fixture
def single_song_video_dict(output_directory):
return {
"download": "https://your.name.here",
"output_options": {"output_directory": output_directory, "file_name": "will_error.mp4"},
# test multi-tags compile
"music_tags": {"genres": ["multi_tag_1", "multi_tag_2"]},
}
class TestDateRange:
def test_date_range(
self,
config,
single_song_video_dict,
output_directory,
subscription_name,
mock_download_collection_entries,
):
ytdl_options = Subscription.from_dict(
config=config,
preset_name=subscription_name,
preset_dict=single_song_video_dict,
).get_ytdl_options(plugins=None, dry_run=False)
assert ytdl_options.download_builder().to_dict() is False

View file

@ -4,7 +4,6 @@ import pytest
from expected_download import assert_expected_downloads from expected_download import assert_expected_downloads
from expected_transaction_log import assert_transaction_log_matches from expected_transaction_log import assert_transaction_log_matches
from ytdl_sub.entries.entry import ytdl_sub_chapters_from_comments
from ytdl_sub.subscriptions.subscription import Subscription from ytdl_sub.subscriptions.subscription import Subscription

View file

View file

@ -0,0 +1,108 @@
import re
from typing import Any
from typing import Dict
import pytest
from conftest import get_match_filters
from ytdl_sub.config.config_file import ConfigFile
from ytdl_sub.subscriptions.subscription import Subscription
from ytdl_sub.utils.exceptions import ValidationException
@pytest.fixture
def preset_dict(output_directory) -> Dict[str, Any]:
return {
"download": "https://your.name.here",
"output_options": {"output_directory": output_directory, "file_name": "will_error.mp4"},
}
class TestDateRange:
@pytest.mark.parametrize("date_range_type", ["upload_date", "release_date"])
def test_date_range_type(
self,
default_config: ConfigFile,
preset_dict: Dict[str, Any],
output_directory: str,
date_range_type: str,
):
preset_dict["date_range"] = {
"before": "20250530",
"after": "20250510",
"type": date_range_type,
}
sub = Subscription.from_dict(
config=default_config,
preset_name="test_date_range",
preset_dict=preset_dict,
)
metadata_filter, metadata_breaking_filter = get_match_filters(
subscription=sub, dry_run=False, download_filters=False
)
assert metadata_filter == [
f"!is_live & !is_upcoming & !post_live & {date_range_type} < 20250530"
]
assert metadata_breaking_filter == [f"{date_range_type} >= 20250510"]
download_filter, download_breaking_filter = get_match_filters(
subscription=sub, dry_run=False, download_filters=True
)
assert not download_filter
assert not download_breaking_filter
def test_date_range_breaks_false(
self,
default_config: ConfigFile,
preset_dict: Dict[str, Any],
output_directory: str,
):
preset_dict["date_range"] = {
"before": "20250530",
"after": "20250510",
"breaks": False,
}
sub = Subscription.from_dict(
config=default_config,
preset_name="test_date_range",
preset_dict=preset_dict,
)
metadata_filter, metadata_breaking_filter = get_match_filters(
subscription=sub, dry_run=False, download_filters=False
)
assert metadata_filter == [
f"!is_live & !is_upcoming & !post_live & upload_date < 20250530 & upload_date >= 20250510"
]
assert not metadata_breaking_filter
download_filter, download_breaking_filter = get_match_filters(
subscription=sub, dry_run=False, download_filters=True
)
assert not download_filter
assert not download_breaking_filter
def test_date_range_invalid_type(
self,
default_config: ConfigFile,
preset_dict: Dict[str, Any],
output_directory: str,
):
preset_dict["date_range"] = {
"before": "20250530",
"after": "20250510",
"type": "no",
}
error_msg = (
"Validation error in test_date_range.date_range.type: "
"Must be one of the following values: release_date, upload_date"
)
with pytest.raises(ValidationException, match=re.escape(error_msg)):
Subscription.from_dict(
config=default_config,
preset_name="test_date_range",
preset_dict=preset_dict,
).download(dry_run=False)