[FEATURE] Filter Keywords prebuilt preset

This commit is contained in:
Jesse Bannon 2024-10-05 00:21:40 -07:00
parent 37ef14cc17
commit ecdc786e1c
9 changed files with 151 additions and 32 deletions

View file

@ -20,9 +20,10 @@ class ErrorFunctions:
Explicitly throw an error with the provided assert message if ``value`` evaluates to Explicitly throw an error with the provided assert message if ``value`` evaluates to
False. If it evaluates to True, it will return ``value``. False. If it evaluates to True, it will return ``value``.
""" """
if not bool(value.value): evaluated_val = value.value()
if not bool(evaluated_val.value):
raise UserThrownRuntimeError(assert_message) raise UserThrownRuntimeError(assert_message)
return value return evaluated_val
@staticmethod @staticmethod
def assert_then( def assert_then(
@ -35,7 +36,7 @@ class ErrorFunctions:
""" """
if not bool(value.value): if not bool(value.value):
raise UserThrownRuntimeError(assert_message) raise UserThrownRuntimeError(assert_message)
return ret return ret.value()
@staticmethod @staticmethod
def assert_eq( def assert_eq(
@ -46,9 +47,10 @@ class ErrorFunctions:
Explicitly throw an error with the provided assert message if ``value`` does not equal Explicitly throw an error with the provided assert message if ``value`` does not equal
``equals``. If they do equal, then return ``value``. ``equals``. If they do equal, then return ``value``.
""" """
if not value.value == equals.value: evaluated_val = value.value()
if not evaluated_val.value == equals.value:
raise UserThrownRuntimeError(assert_message) raise UserThrownRuntimeError(assert_message)
return value return evaluated_val
@staticmethod @staticmethod
def assert_ne( def assert_ne(
@ -59,6 +61,7 @@ class ErrorFunctions:
Explicitly throw an error with the provided assert message if ``value`` equals Explicitly throw an error with the provided assert message if ``value`` equals
``equals``. If they do equal, then return ``value``. ``equals``. If they do equal, then return ``value``.
""" """
if value.value == equals.value: evaluated_value = value.value()
if evaluated_value.value == equals.value:
raise UserThrownRuntimeError(assert_message) raise UserThrownRuntimeError(assert_message)
return value return evaluated_value

View file

@ -259,7 +259,7 @@ class BuiltInFunction(Function, BuiltInFunctionType):
resolved_variables: Dict[Variable, Resolvable], resolved_variables: Dict[Variable, Resolvable],
custom_functions: Dict[str, "VariableDependency"], custom_functions: Dict[str, "VariableDependency"],
) -> Resolvable: ) -> Resolvable:
# TODO: Make conditionals not execute all branches!!! # Ensure conditionals do not execute all branches
conditional_return_args = self.function_spec.conditional_arg_indices( conditional_return_args = self.function_spec.conditional_arg_indices(
num_input_args=len(self.args) num_input_args=len(self.args)
) )

View file

@ -208,6 +208,10 @@ class FunctionSpec:
return list(range(1, num_input_args, 2)) + [num_input_args - 1] return list(range(1, num_input_args, 2)) + [num_input_args - 1]
if self.function_name == "if_passthrough": if self.function_name == "if_passthrough":
return [0, 1] # true-passthrough, false-passthrough return [0, 1] # true-passthrough, false-passthrough
if self.function_name in ("assert", "assert_eq", "assert_ne"):
return [0]
if self.function_name == "assert_then":
return [1]
return [] return []
@property @property

View file

@ -1,8 +1,9 @@
import re import re
import pytest import pytest
from expected_transaction_log import assert_transaction_log_matches from expected_transaction_log import assert_transaction_log_matches
from ytdl_sub.script.utils.exceptions import UserThrownRuntimeError
from ytdl_sub.subscriptions.subscription import Subscription from ytdl_sub.subscriptions.subscription import Subscription
from ytdl_sub.utils.exceptions import ValidationException from ytdl_sub.utils.exceptions import ValidationException
@ -14,12 +15,10 @@ def filter_subscription_dict(output_directory):
"Plex TV Show by Date", "Plex TV Show by Date",
"Filter Keywords", "Filter Keywords",
], ],
"overrides": { "overrides": {"url": "https://your.name.here", "tv_show_directory": output_directory},
"url": "https://your.name.here",
"tv_show_directory": output_directory
}
} }
class TestFilterKeywords: class TestFilterKeywords:
def test_no_overrides( def test_no_overrides(
@ -36,7 +35,7 @@ class TestFilterKeywords:
preset_dict=filter_subscription_dict, preset_dict=filter_subscription_dict,
) )
with mock_download_collection_entries( with mock_download_collection_entries(
is_youtube_channel=False, num_urls=1, is_dry_run=True is_youtube_channel=False, num_urls=1, is_dry_run=True
): ):
transaction_log = subscription.download(dry_run=True) transaction_log = subscription.download(dry_run=True)
@ -59,7 +58,7 @@ class TestFilterKeywords:
): ):
filter_subscription_dict["overrides"][f"title_{filter_mode}_keywords"] = [ filter_subscription_dict["overrides"][f"title_{filter_mode}_keywords"] = [
"not included", "not included",
"MOCK ENTRY 20-3" "MOCK ENTRY 20-3",
] ]
subscription = Subscription.from_dict( subscription = Subscription.from_dict(
config=config, config=config,
@ -67,7 +66,7 @@ class TestFilterKeywords:
preset_dict=filter_subscription_dict, preset_dict=filter_subscription_dict,
) )
with mock_download_collection_entries( with mock_download_collection_entries(
is_youtube_channel=False, num_urls=1, is_dry_run=True is_youtube_channel=False, num_urls=1, is_dry_run=True
): ):
transaction_log = subscription.download(dry_run=True) transaction_log = subscription.download(dry_run=True)
@ -75,7 +74,7 @@ class TestFilterKeywords:
assert_transaction_log_matches( assert_transaction_log_matches(
output_directory=output_directory, output_directory=output_directory,
transaction_log=transaction_log, transaction_log=transaction_log,
transaction_log_summary_file_name=f"integration/prebuilt_presets/filter_keywords_{filter_mode}.txt", transaction_log_summary_file_name=f"integration/prebuilt_presets/title_filter_keywords_{filter_mode}.txt",
) )
@pytest.mark.parametrize("filter_mode", ["include", "exclude"]) @pytest.mark.parametrize("filter_mode", ["include", "exclude"])
@ -89,8 +88,8 @@ class TestFilterKeywords:
filter_mode: str, filter_mode: str,
): ):
filter_subscription_dict["overrides"][f"description_{filter_mode}_keywords"] = [ filter_subscription_dict["overrides"][f"description_{filter_mode}_keywords"] = [
"not included", "no filter here",
"MOCK ENTRY 20-3" "description",
] ]
subscription = Subscription.from_dict( subscription = Subscription.from_dict(
config=config, config=config,
@ -98,7 +97,7 @@ class TestFilterKeywords:
preset_dict=filter_subscription_dict, preset_dict=filter_subscription_dict,
) )
with mock_download_collection_entries( with mock_download_collection_entries(
is_youtube_channel=False, num_urls=1, is_dry_run=True is_youtube_channel=False, num_urls=1, is_dry_run=True
): ):
transaction_log = subscription.download(dry_run=True) transaction_log = subscription.download(dry_run=True)
@ -106,25 +105,67 @@ class TestFilterKeywords:
assert_transaction_log_matches( assert_transaction_log_matches(
output_directory=output_directory, output_directory=output_directory,
transaction_log=transaction_log, transaction_log=transaction_log,
transaction_log_summary_file_name=f"integration/prebuilt_presets/filter_keywords_{filter_mode}.txt", transaction_log_summary_file_name=f"integration/prebuilt_presets/description_filter_keywords_{filter_mode}.txt",
) )
@pytest.mark.parametrize(
"keyword_variable",
[
"title_include_keywords",
"title_exclude_keywords",
"description_include_keywords",
"description_exclude_keywords",
],
)
def test_error_not_list_type( def test_error_not_list_type(
self, self,
config, config,
filter_subscription_dict, filter_subscription_dict,
output_directory, output_directory,
subscription_name, subscription_name,
mock_download_collection_entries, mock_download_collection_entries,
keyword_variable,
): ):
filter_subscription_dict["overrides"][f"description_include_keywords"] = "not list" filter_subscription_dict["overrides"][keyword_variable] = "not array"
subscription = Subscription.from_dict( subscription = Subscription.from_dict(
config=config, config=config,
preset_name=subscription_name, preset_name=subscription_name,
preset_dict=filter_subscription_dict, preset_dict=filter_subscription_dict,
) )
with mock_download_collection_entries( with (
is_youtube_channel=False, num_urls=1, is_dry_run=True mock_download_collection_entries(is_youtube_channel=False, num_urls=1, is_dry_run=True),
pytest.raises(UserThrownRuntimeError, match=f"{keyword_variable} must be an array"),
): ):
transaction_log = subscription.download(dry_run=True) _ = subscription.download(dry_run=True)
@pytest.mark.parametrize(
"keyword_variable",
[
"title_include_keywords",
"title_exclude_keywords",
"description_include_keywords",
"description_exclude_keywords",
],
)
def test_error_not_string_keyword(
self,
config,
filter_subscription_dict,
output_directory,
subscription_name,
mock_download_collection_entries,
keyword_variable,
):
filter_subscription_dict["overrides"][keyword_variable] = "{['str', ['nested array not']]}"
subscription = Subscription.from_dict(
config=config,
preset_name=subscription_name,
preset_dict=filter_subscription_dict,
)
with (
mock_download_collection_entries(is_youtube_channel=False, num_urls=1, is_dry_run=True),
pytest.raises(UserThrownRuntimeError, match="filter keywords must be strings"),
):
_ = subscription.download(dry_run=True)

View file

@ -2,7 +2,7 @@ import os
import shutil import shutil
from pathlib import Path from pathlib import Path
REGENERATE_FIXTURES: bool = True REGENERATE_FIXTURES: bool = False
RESOURCE_PATH: Path = Path("tests") / "resources" RESOURCE_PATH: Path = Path("tests") / "resources"
_FILE_FIXTURE_PATH: Path = RESOURCE_PATH / "file_fixtures" _FILE_FIXTURE_PATH: Path = RESOURCE_PATH / "file_fixtures"

View file

@ -0,0 +1,51 @@
Files created:
----------------------------------------
{output_directory}
.ytdl-sub-subscription_test-download-archive.json
{output_directory}/Season 2020
s2020.e080801 - Mock Entry --thumb.jpg
s2020.e080801 - Mock Entry -.info.json
s2020.e080801 - Mock Entry -.mp4
Video Tags:
contentRating: TV-14
date: 2020-08-08
episode_id: 80801
genre: ytdl-sub
show: subscription_test
synopsis:
https://20-2.com
The Description
title: 2020-08-08 - Mock Entry 20-2
year: 2020
s2020.e080802 - Mock Entry --thumb.jpg
s2020.e080802 - Mock Entry -.info.json
s2020.e080802 - Mock Entry -.mp4
Video Tags:
contentRating: TV-14
date: 2020-08-08
episode_id: 80802
genre: ytdl-sub
show: subscription_test
synopsis:
https://20-1.com
The Description
title: 2020-08-08 - Mock Entry 20-1
year: 2020
{output_directory}/Season 2021
s2021.e080801 - Mock Entry --thumb.jpg
s2021.e080801 - Mock Entry -.info.json
s2021.e080801 - Mock Entry -.mp4
Video Tags:
contentRating: TV-14
date: 2021-08-08
episode_id: 80801
genre: ytdl-sub
show: subscription_test
synopsis:
https://21-1.com
The Description
title: 2021-08-08 - Mock Entry 21-1
year: 2021

View file

@ -0,0 +1,20 @@
Files created:
----------------------------------------
{output_directory}
.ytdl-sub-subscription_test-download-archive.json
{output_directory}/Season 2020
s2020.e080701 - Mock Entry --thumb.jpg
s2020.e080701 - Mock Entry -.info.json
s2020.e080701 - Mock Entry -.mp4
Video Tags:
contentRating: TV-14
date: 2020-08-07
episode_id: 80701
genre: ytdl-sub
show: subscription_test
synopsis:
https://20-3.com
The Description
title: 2020-08-07 - Mock Entry 20-3
year: 2020