Future resolvable

This commit is contained in:
Jesse Bannon 2023-12-06 23:13:43 -08:00
parent 321e45b75c
commit abf60f5052
10 changed files with 43 additions and 38 deletions

View file

@ -2,7 +2,6 @@ from typing import List
from typing import Optional from typing import Optional
from ytdl_sub.script.types.array import Array from ytdl_sub.script.types.array import Array
from ytdl_sub.script.types.array import ResolvedArray
from ytdl_sub.script.types.resolvable import AnyArgument from ytdl_sub.script.types.resolvable import AnyArgument
from ytdl_sub.script.types.resolvable import Boolean from ytdl_sub.script.types.resolvable import Boolean
from ytdl_sub.script.types.resolvable import Integer from ytdl_sub.script.types.resolvable import Integer
@ -23,7 +22,7 @@ class ArrayFunctions:
for array in arrays: for array in arrays:
output.extend(array.value) output.extend(array.value)
return ResolvedArray(output) return Array(output)
@staticmethod @staticmethod
def array_at(array: Array, idx: Integer) -> Resolvable: def array_at(array: Array, idx: Integer) -> Resolvable:
@ -61,8 +60,8 @@ class ArrayFunctions:
Returns the slice of the Array. Returns the slice of the Array.
""" """
if end is not None: if end is not None:
return ResolvedArray(array.value[start.value : end.value]) return Array(array.value[start.value : end.value])
return ResolvedArray(array.value[start.value :]) return Array(array.value[start.value :])
@staticmethod @staticmethod
def array_flatten(array: Array) -> Array: def array_flatten(array: Array) -> Array:
@ -76,14 +75,14 @@ class ArrayFunctions:
else: else:
output.append(elem) output.append(elem)
return ResolvedArray(output) return Array(output)
@staticmethod @staticmethod
def array_reverse(array: Array) -> Array: def array_reverse(array: Array) -> Array:
""" """
Reverse an Array. Reverse an Array.
""" """
return ResolvedArray(list(reversed(array.value))) return Array(list(reversed(array.value)))
# pylint: disable=unused-argument # pylint: disable=unused-argument
@ -92,7 +91,7 @@ class ArrayFunctions:
""" """
Apply a lambda function on every element in the Array. Apply a lambda function on every element in the Array.
""" """
return ResolvedArray([ResolvedArray([val]) for val in array.value]) return Array([Array([val]) for val in array.value])
@staticmethod @staticmethod
def array_enumerate(array: Array, lambda_function: LambdaTwo) -> Array: def array_enumerate(array: Array, lambda_function: LambdaTwo) -> Array:
@ -100,8 +99,6 @@ class ArrayFunctions:
Apply a lambda function on every element in the Array, where each arg Apply a lambda function on every element in the Array, where each arg
passed to the lambda function is ``idx, element`` as two separate args. passed to the lambda function is ``idx, element`` as two separate args.
""" """
return ResolvedArray( return Array([Array([Integer(idx), val]) for idx, val in enumerate(array.value)])
[ResolvedArray([Integer(idx), val]) for idx, val in enumerate(array.value)]
)
# pylint: enable=unused-argument # pylint: enable=unused-argument

View file

@ -1,7 +1,6 @@
from typing import Optional from typing import Optional
from ytdl_sub.script.types.array import Array from ytdl_sub.script.types.array import Array
from ytdl_sub.script.types.array import ResolvedArray
from ytdl_sub.script.types.map import Map from ytdl_sub.script.types.map import Map
from ytdl_sub.script.types.resolvable import AnyArgument from ytdl_sub.script.types.resolvable import AnyArgument
from ytdl_sub.script.types.resolvable import Boolean from ytdl_sub.script.types.resolvable import Boolean
@ -43,7 +42,7 @@ class MapFunctions:
Apply a lambda function on the Map, where each arg Apply a lambda function on the Map, where each arg
passed to the lambda function is ``key, value`` as two separate args. passed to the lambda function is ``key, value`` as two separate args.
""" """
return ResolvedArray([ResolvedArray([key, value]) for key, value in mapping.value.items()]) return Array([Array([key, value]) for key, value in mapping.value.items()])
@staticmethod @staticmethod
def map_enumerate(mapping: Map, lambda_function: LambdaThree) -> Array: def map_enumerate(mapping: Map, lambda_function: LambdaThree) -> Array:
@ -51,9 +50,9 @@ class MapFunctions:
Apply a lambda function on the Map, where each arg Apply a lambda function on the Map, where each arg
passed to the lambda function is ``idx, key, value`` as three separate args. passed to the lambda function is ``idx, key, value`` as three separate args.
""" """
return ResolvedArray( return Array(
[ [
ResolvedArray([Integer(idx), key_value[0], key_value[1]]) Array([Integer(idx), key_value[0], key_value[1]])
for idx, key_value in enumerate(mapping.value.items()) for idx, key_value in enumerate(mapping.value.items())
] ]
) )

View file

@ -3,17 +3,14 @@ from typing import AnyStr
from typing import Match from typing import Match
from ytdl_sub.script.types.array import Array from ytdl_sub.script.types.array import Array
from ytdl_sub.script.types.array import ResolvedArray
from ytdl_sub.script.types.resolvable import String from ytdl_sub.script.types.resolvable import String
def _re_output_to_array(re_out: Match[AnyStr] | None) -> ResolvedArray: def _re_output_to_array(re_out: Match[AnyStr] | None) -> Array:
if re_out is None: if re_out is None:
return ResolvedArray([]) return Array([])
return ResolvedArray( return Array(list([String(re_out.string)]) + list(String(group) for group in re_out.groups()))
list([String(re_out.string)]) + list(String(group) for group in re_out.groups())
)
class RegexFunctions: class RegexFunctions:

View file

@ -2,9 +2,11 @@ from dataclasses import dataclass
from typing import Any from typing import Any
from typing import Dict from typing import Dict
from typing import List from typing import List
from typing import Type
from ytdl_sub.script.types.resolvable import AnyArgument from ytdl_sub.script.types.resolvable import AnyArgument
from ytdl_sub.script.types.resolvable import Argument from ytdl_sub.script.types.resolvable import Argument
from ytdl_sub.script.types.resolvable import FutureResolvable
from ytdl_sub.script.types.resolvable import NonHashable from ytdl_sub.script.types.resolvable import NonHashable
from ytdl_sub.script.types.resolvable import Resolvable from ytdl_sub.script.types.resolvable import Resolvable
from ytdl_sub.script.types.resolvable import ResolvableToJson from ytdl_sub.script.types.resolvable import ResolvableToJson
@ -13,7 +15,7 @@ from ytdl_sub.script.types.variable_dependency import VariableDependency
@dataclass(frozen=True) @dataclass(frozen=True)
class Array(NonHashable): class _Array(NonHashable):
value: List[Resolvable] value: List[Resolvable]
@classmethod @classmethod
@ -22,7 +24,7 @@ class Array(NonHashable):
@dataclass(frozen=True) @dataclass(frozen=True)
class UnresolvedArray(Array, VariableDependency, AnyArgument): class UnresolvedArray(_Array, VariableDependency, FutureResolvable):
value: List[Argument] value: List[Argument]
@property @property
@ -34,7 +36,7 @@ class UnresolvedArray(Array, VariableDependency, AnyArgument):
resolved_variables: Dict[Variable, Resolvable], resolved_variables: Dict[Variable, Resolvable],
custom_functions: Dict[str, "VariableDependency"], custom_functions: Dict[str, "VariableDependency"],
) -> Resolvable: ) -> Resolvable:
return ResolvedArray( return Array(
[ [
self._resolve_argument_type( self._resolve_argument_type(
arg=arg, arg=arg,
@ -45,9 +47,12 @@ class UnresolvedArray(Array, VariableDependency, AnyArgument):
] ]
) )
def future_resolvable_type(self) -> Type[Resolvable]:
return Array
@dataclass(frozen=True) @dataclass(frozen=True)
class ResolvedArray(Array, ResolvableToJson): class Array(_Array, ResolvableToJson):
@property @property
def native(self) -> Any: def native(self) -> Any:
return [val.native for val in self.value] return [val.native for val in self.value]

View file

@ -9,7 +9,7 @@ from typing import Type
from typing import Union from typing import Union
from ytdl_sub.script.functions import Functions from ytdl_sub.script.functions import Functions
from ytdl_sub.script.types.array import ResolvedArray from ytdl_sub.script.types.array import Array
from ytdl_sub.script.types.array import UnresolvedArray from ytdl_sub.script.types.array import UnresolvedArray
from ytdl_sub.script.types.resolvable import Argument from ytdl_sub.script.types.resolvable import Argument
from ytdl_sub.script.types.resolvable import BuiltInFunctionType from ytdl_sub.script.types.resolvable import BuiltInFunctionType
@ -151,7 +151,7 @@ class BuiltInFunction(Function, BuiltInFunctionType):
f"Runtime error occurred when executing the function %{self.name}: {str(exc)}" f"Runtime error occurred when executing the function %{self.name}: {str(exc)}"
) from exc ) from exc
assert isinstance(lambda_args, ResolvedArray) assert isinstance(lambda_args, Array)
return self._resolve_argument_type( return self._resolve_argument_type(
arg=UnresolvedArray( arg=UnresolvedArray(

View file

@ -87,6 +87,13 @@ class Resolvable(AnyArgument, ABC):
return self.value return self.value
@dataclass(frozen=True)
class FutureResolvable(AnyArgument, ABC):
@abstractmethod
def future_resolvable_type(self) -> Type[Resolvable]:
pass
@dataclass(frozen=True) @dataclass(frozen=True)
class Hashable(Resolvable, ABC): class Hashable(Resolvable, ABC):
pass pass

View file

@ -12,6 +12,7 @@ from typing import get_origin
from ytdl_sub.script.types.resolvable import Argument from ytdl_sub.script.types.resolvable import Argument
from ytdl_sub.script.types.resolvable import BuiltInFunctionType from ytdl_sub.script.types.resolvable import BuiltInFunctionType
from ytdl_sub.script.types.resolvable import FunctionType from ytdl_sub.script.types.resolvable import FunctionType
from ytdl_sub.script.types.resolvable import FutureResolvable
from ytdl_sub.script.types.resolvable import Lambda from ytdl_sub.script.types.resolvable import Lambda
from ytdl_sub.script.types.resolvable import LambdaThree from ytdl_sub.script.types.resolvable import LambdaThree
from ytdl_sub.script.types.resolvable import LambdaTwo from ytdl_sub.script.types.resolvable import LambdaTwo
@ -65,11 +66,12 @@ def is_type_compatible(
arg_type: Type[NamedType] = arg.__class__ arg_type: Type[NamedType] = arg.__class__
if isinstance(arg, BuiltInFunctionType): if isinstance(arg, BuiltInFunctionType):
arg_type = arg.output_type() # built-in function arg_type = arg.output_type() # built-in function
elif isinstance(arg, FutureResolvable):
arg_type = arg.future_resolvable_type()
elif isinstance(arg, FunctionType): elif isinstance(arg, FunctionType):
return True # custom-function, can be anything, so pass for now return True # custom-function, can be anything, so pass for now
elif isinstance(arg, Variable): elif isinstance(arg, Variable):
return True # unresolved variables can be anything, so pass for now return True # unresolved variables can be anything, so pass for now
if is_union(expected_arg_type): if is_union(expected_arg_type):
# See if the arg is a valid against the union # See if the arg is a valid against the union
valid_type = False valid_type = False

View file

@ -6,8 +6,7 @@ from ytdl_sub.script.parser import _UNEXPECTED_CHAR_ARGUMENT
from ytdl_sub.script.parser import _UNEXPECTED_COMMA_ARGUMENT from ytdl_sub.script.parser import _UNEXPECTED_COMMA_ARGUMENT
from ytdl_sub.script.parser import ParsedArgType from ytdl_sub.script.parser import ParsedArgType
from ytdl_sub.script.script import Script from ytdl_sub.script.script import Script
from ytdl_sub.script.types.array import ResolvedArray from ytdl_sub.script.types.array import Array
from ytdl_sub.script.types.resolvable import Boolean
from ytdl_sub.script.types.resolvable import Float from ytdl_sub.script.types.resolvable import Float
from ytdl_sub.script.types.resolvable import String from ytdl_sub.script.types.resolvable import String
from ytdl_sub.script.utils.exceptions import InvalidSyntaxException from ytdl_sub.script.utils.exceptions import InvalidSyntaxException
@ -16,7 +15,7 @@ from ytdl_sub.script.utils.exceptions import InvalidSyntaxException
class TestArray: class TestArray:
def test_return(self): def test_return(self):
assert Script({"array": "{['a', 3.14]}"}).resolve() == { assert Script({"array": "{['a', 3.14]}"}).resolve() == {
"array": ResolvedArray([String("a"), Float(3.14)]) "array": Array([String("a"), Float(3.14)])
} }
def test_return_as_str(self): def test_return_as_str(self):
@ -28,13 +27,13 @@ class TestArray:
assert Script( assert Script(
{"array": "{['level1', ['level2', ['level3', 'level3'], 'level2'], 'level1']}"} {"array": "{['level1', ['level2', ['level3', 'level3'], 'level2'], 'level1']}"}
).resolve() == { ).resolve() == {
"array": ResolvedArray( "array": Array(
[ [
String("level1"), String("level1"),
ResolvedArray( Array(
[ [
String("level2"), String("level2"),
ResolvedArray([String("level3"), String("level3")]), Array([String("level3"), String("level3")]),
String("level2"), String("level2"),
], ],
), ),
@ -53,7 +52,7 @@ class TestArray:
], ],
) )
def test_empty(self, array: str): def test_empty(self, array: str):
assert Script({"array": array}).resolve() == {"array": ResolvedArray([])} assert Script({"array": array}).resolve() == {"array": Array([])}
@pytest.mark.parametrize( @pytest.mark.parametrize(
"array", "array",

View file

@ -3,7 +3,7 @@ import re
import pytest import pytest
from ytdl_sub.script.script import Script from ytdl_sub.script.script import Script
from ytdl_sub.script.types.array import ResolvedArray from ytdl_sub.script.types.array import Array
from ytdl_sub.script.types.resolvable import Integer from ytdl_sub.script.types.resolvable import Integer
from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments
@ -12,7 +12,7 @@ class TestLambdaFunction:
def test_lambda_with_custom_function(self): def test_lambda_with_custom_function(self):
assert Script( assert Script(
{"%times_two": "{%mul($0, 2)}", "wip": "{%array_apply([1, 2, 3], %times_two)}"} {"%times_two": "{%mul($0, 2)}", "wip": "{%array_apply([1, 2, 3], %times_two)}"}
).resolve() == {"wip": ResolvedArray([Integer(2), Integer(4), Integer(6)])} ).resolve() == {"wip": Array([Integer(2), Integer(4), Integer(6)])}
def test_conditional_lambda_with_custom_functions(self): def test_conditional_lambda_with_custom_functions(self):
assert Script( assert Script(
@ -21,7 +21,7 @@ class TestLambdaFunction:
"%times_two": "{%mul($0, 2)}", "%times_two": "{%mul($0, 2)}",
"wip": "{%array_apply([1, 2, 3], %if(False, %times_two, %times_three))}", "wip": "{%array_apply([1, 2, 3], %if(False, %times_two, %times_three))}",
} }
).resolve() == {"wip": ResolvedArray([Integer(3), Integer(6), Integer(9)])} ).resolve() == {"wip": Array([Integer(3), Integer(6), Integer(9)])}
def test_nested_custom_functions(self): def test_nested_custom_functions(self):
assert Script( assert Script(

View file

@ -11,7 +11,6 @@ from ytdl_sub.script.parser import MAP_MISSING_KEY
from ytdl_sub.script.parser import ParsedArgType from ytdl_sub.script.parser import ParsedArgType
from ytdl_sub.script.script import Script from ytdl_sub.script.script import Script
from ytdl_sub.script.types.map import ResolvedMap from ytdl_sub.script.types.map import ResolvedMap
from ytdl_sub.script.types.resolvable import Boolean
from ytdl_sub.script.types.resolvable import Float from ytdl_sub.script.types.resolvable import Float
from ytdl_sub.script.types.resolvable import String from ytdl_sub.script.types.resolvable import String
from ytdl_sub.script.utils.exceptions import InvalidSyntaxException from ytdl_sub.script.utils.exceptions import InvalidSyntaxException