scripting functions

This commit is contained in:
Jesse Bannon 2023-12-28 10:20:56 -08:00
parent 511df8fb5b
commit ba0a369692
4 changed files with 105 additions and 34 deletions

View file

@ -17,6 +17,13 @@ array_apply
Apply a lambda function on every element in the Array. Apply a lambda function on every element in the Array.
array_apply_fixed
~~~~~~~~~~~~~~~~~
``array_apply_fixed(array: Array, fixed_argument: AnyArgument, lambda2_function: LambdaTwo, reverse_args: Optional[Boolean]) -> Array``
Apply a lambda function on every element in the Array, with ``fixed_argument``
passed as a second argument to every invocation.
array_at array_at
~~~~~~~~ ~~~~~~~~
``array_at(array: Array, idx: Integer) -> AnyArgument`` ``array_at(array: Array, idx: Integer) -> AnyArgument``
@ -42,6 +49,13 @@ array_extend
Combine multiple Arrays into a single Array. Combine multiple Arrays into a single Array.
array_first
~~~~~~~~~~~
``array_first(array: Array, fallback: AnyArgument) -> AnyArgument``
Returns the first element whose boolean conversion is True. Returns fallback
if all elements evaluate to False.
array_flatten array_flatten
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
``array_flatten(array: Array) -> Array`` ``array_flatten(array: Array) -> Array``
@ -55,6 +69,12 @@ array_index
Return the index of the value within the Array if it exists. If it does not, it will Return the index of the value within the Array if it exists. If it does not, it will
throw an error. throw an error.
array_overlay
~~~~~~~~~~~~~
``array_overlay(array: Array, overlap: Array, only_missing: Optional[Boolean]) -> Array``
Overlaps ``overlap`` onto ``array``. Can optionally only overlay missing indices.
array_product array_product
~~~~~~~~~~~~~ ~~~~~~~~~~~~~
``array_product(arrays: Array, ...) -> Array`` ``array_product(arrays: Array, ...) -> Array``
@ -119,6 +139,12 @@ gte
``>=`` operator. Returns True if left >= right. False otherwise. ``>=`` operator. Returns True if left >= right. False otherwise.
is_null
~~~~~~~
``is_null(value: AnyArgument) -> Boolean``
Returns True if a value is null (i.e. an empty string). False otherwise.
lt lt
~~ ~~
``lt(left: AnyArgument, right: AnyArgument) -> Boolean`` ``lt(left: AnyArgument, right: AnyArgument) -> Boolean``
@ -191,6 +217,27 @@ assert
Explicitly throw an error with the provided assert message if ``value`` evaluates to False. Explicitly throw an error with the provided assert message if ``value`` evaluates to False.
If it evaluates to True, it will return ``value``. If it evaluates to True, it will return ``value``.
assert_eq
~~~~~~~~~
``assert_eq(value: ReturnableArgument, equals: AnyArgument, assert_message: String) -> ReturnableArgument``
Explicitly throw an error with the provided assert message if ``value`` does not equal
``equals``. If they do equal, then return ``value``.
assert_ne
~~~~~~~~~
``assert_ne(value: ReturnableArgument, equals: AnyArgument, assert_message: String) -> ReturnableArgument``
Explicitly throw an error with the provided assert message if ``value`` equals
``equals``. If they do equal, then return ``value``.
assert_then
~~~~~~~~~~~
``assert_then(value: AnyArgument, ret: ReturnableArgument, assert_message: String) -> ReturnableArgument``
Explicitly throw an error with the provided assert message if ``value`` evaluates to False.
If it evaluates to True, it will return ``ret``.
throw throw
~~~~~ ~~~~~
``throw(error_message: String) -> AnyArgument`` ``throw(error_message: String) -> AnyArgument``
@ -321,6 +368,12 @@ sub
Regex Functions Regex Functions
--------------- ---------------
regex_capture_groups
~~~~~~~~~~~~~~~~~~~~
``regex_capture_groups(regex: String) -> Integer``
Returns number of capture groups in regex
regex_fullmatch regex_fullmatch
~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~
``regex_fullmatch(regex: String, string: String) -> Array`` ``regex_fullmatch(regex: String, string: String) -> Array``
@ -360,6 +413,12 @@ concat
Concatenate multiple Strings into a single String. Concatenate multiple Strings into a single String.
contains
~~~~~~~~
``contains(string: String, contains: String) -> Boolean``
Returns True if ``contains`` is in ``string``. False otherwise.
lower lower
~~~~~ ~~~~~
``lower(string: String) -> String`` ``lower(string: String) -> String``

View file

@ -1,11 +1,22 @@
from typing import Type
from tools.docgen.docgen import DocGen
from tools.docgen.entry_variables import EntryVariableDocGen from tools.docgen.entry_variables import EntryVariableDocGen
from tools.docgen.scripting_functions import ScriptingFunctionsDocGen
from ytdl_sub.utils.file_handler import get_file_md5_hash from ytdl_sub.utils.file_handler import get_file_md5_hash
from ytdl_sub.utils.file_handler import get_md5_hash from ytdl_sub.utils.file_handler import get_md5_hash
def _test_doc_gen(doc_gen: Type[DocGen]) -> None:
expected_md5_hash = get_md5_hash(doc_gen.generate_and_maybe_write_to_file())
md5_hash = get_file_md5_hash(doc_gen.LOCATION)
assert md5_hash == expected_md5_hash
class TestDocGen: class TestDocGen:
def test_entry_variables_generated(self): def test_entry_variables_generated(self):
md5_hash = get_file_md5_hash(EntryVariableDocGen.LOCATION) _test_doc_gen(EntryVariableDocGen)
expected_md5_hash = get_md5_hash(EntryVariableDocGen.generate_and_maybe_write_to_file())
assert md5_hash == expected_md5_hash def test_scripting_functions_generated(self):
_test_doc_gen(ScriptingFunctionsDocGen)

View file

@ -11,27 +11,25 @@ from tools.docgen.utils import section
from ytdl_sub.entries.script.variable_definitions import VariableDefinitions from ytdl_sub.entries.script.variable_definitions import VariableDefinitions
def _variable_class_to_name(obj: Type[Any]) -> str:
assert "VariableDefinitions" in obj.__name__, f"{obj.__name__} doesnt have VariableDefinitions"
return (
camel_case_to_human(obj.__name__)
.replace("Variable Definitions", "Variables")
.replace("Ytdl Sub", "Ytdl-Sub")
)
class EntryVariableDocGen(DocGen): class EntryVariableDocGen(DocGen):
LOCATION = Path("docs/source/config_reference/scripting/entry_variables.rst") LOCATION = Path("docs/source/config_reference/scripting/entry_variables.rst")
@classmethod
def _variable_class_to_name(cls, obj: Type[Any]) -> str:
assert (
"VariableDefinitions" in obj.__name__
), f"{obj.__name__} doesnt have VariableDefinitions"
return (
camel_case_to_human(obj.__name__)
.replace("Variable Definitions", "Variables")
.replace("Ytdl Sub", "Ytdl-Sub")
)
@classmethod @classmethod
def generate(cls) -> str: def generate(cls) -> str:
docs = section("Entry Variables", level=0) docs = section("Entry Variables", level=0)
parent_objs: Dict[str, Type[Any]] = { parent_objs: Dict[str, Type[Any]] = {
cls._variable_class_to_name(obj): obj for obj in VariableDefinitions.__bases__ _variable_class_to_name(obj): obj for obj in VariableDefinitions.__bases__
} }
for name in sorted(parent_objs.keys()): for name in sorted(parent_objs.keys()):

View file

@ -1,13 +1,14 @@
import inspect import inspect
from pathlib import Path
from typing import Any from typing import Any
from typing import Dict from typing import Dict
from typing import Optional from typing import Optional
from typing import Type from typing import Type
from tools.docgen.docgen import DocGen
from tools.docgen.utils import camel_case_to_human from tools.docgen.utils import camel_case_to_human
from tools.docgen.utils import section from tools.docgen.utils import section
from tools.docgen.utils import static_methods from tools.docgen.utils import static_methods
from tools.docgen.utils import to_out_dir
from ytdl_sub.entries.script.custom_functions import CustomFunctions from ytdl_sub.entries.script.custom_functions import CustomFunctions
from ytdl_sub.script.functions import Functions from ytdl_sub.script.functions import Functions
from ytdl_sub.script.utils.type_checking import FunctionSpec from ytdl_sub.script.utils.type_checking import FunctionSpec
@ -51,27 +52,29 @@ def get_function_docstring(
return docs return docs
def generate_function_docs() -> str: class ScriptingFunctionsDocGen(DocGen):
docs = section("Scripting Functions", level=0)
parent_objs: Dict[str, Type[Any]] = { LOCATION = Path("docs/source/config_reference/scripting/scripting_functions.rst")
function_class_to_name(obj): obj for obj in Functions.__bases__
}
parent_objs["Ytdl-Sub Functions"] = CustomFunctions
for name in sorted(parent_objs.keys()): @classmethod
docs += section(name, level=1) def generate(cls) -> str:
docs = section("Scripting Functions", level=0)
for function_name in static_methods(parent_objs[name]): parent_objs: Dict[str, Type[Any]] = {
if display_function_name := maybe_get_function_name(function_name): function_class_to_name(obj): obj for obj in Functions.__bases__
docs += get_function_docstring( }
function_name=function_name, parent_objs["Ytdl-Sub Functions"] = CustomFunctions
display_function_name=display_function_name,
function=getattr(parent_objs[name], function_name),
level=2,
)
return docs for name in sorted(parent_objs.keys()):
docs += section(name, level=1)
for function_name in static_methods(parent_objs[name]):
if display_function_name := maybe_get_function_name(function_name):
docs += get_function_docstring(
function_name=function_name,
display_function_name=display_function_name,
function=getattr(parent_objs[name], function_name),
level=2,
)
to_out_dir(name="scripting_functions.rst", docs=generate_function_docs()) return docs