function type checking wip
This commit is contained in:
parent
c7b41a48ae
commit
9b7ba5cb3e
2 changed files with 43 additions and 5 deletions
|
|
@ -43,7 +43,7 @@ class FunctionInputSpec:
|
||||||
input_arg: ArgumentType,
|
input_arg: ArgumentType,
|
||||||
expected_arg_type: Type[Resolvable | Optional[Resolvable]],
|
expected_arg_type: Type[Resolvable | Optional[Resolvable]],
|
||||||
) -> bool:
|
) -> bool:
|
||||||
if isinstance(input_arg, Function):
|
if isinstance(input_arg, BuiltInFunction):
|
||||||
input_arg_type = input_arg.output_type
|
input_arg_type = input_arg.output_type
|
||||||
elif isinstance(input_arg, Variable):
|
elif isinstance(input_arg, Variable):
|
||||||
return True # unresolved variables can be anything, so pass for now
|
return True # unresolved variables can be anything, so pass for now
|
||||||
|
|
@ -115,7 +115,7 @@ class FunctionInputSpec:
|
||||||
return f"({self.varargs.__name__}, ...)"
|
return f"({self.varargs.__name__}, ...)"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_function(cls, func: "Function") -> "FunctionInputSpec":
|
def from_function(cls, func: "BuiltInFunction") -> "FunctionInputSpec":
|
||||||
if func.arg_spec.varargs:
|
if func.arg_spec.varargs:
|
||||||
return FunctionInputSpec(varargs=func.arg_spec.annotations[func.arg_spec.varargs])
|
return FunctionInputSpec(varargs=func.arg_spec.annotations[func.arg_spec.varargs])
|
||||||
|
|
||||||
|
|
@ -164,7 +164,7 @@ class Function(VariableDependency, ArgumentType, ABC):
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_name_and_args(cls, name: str, args: List[ArgumentType]) -> "Function":
|
def from_name_and_args(cls, name: str, args: List[ArgumentType]) -> "Function":
|
||||||
if hasattr(Functions, name) or hasattr(Functions, name + "_"):
|
if hasattr(Functions, name) or hasattr(Functions, name + "_"):
|
||||||
return BuiltInFunction(name=name, args=args)
|
return BuiltInFunction(name=name, args=args).validate_args()
|
||||||
|
|
||||||
return CustomFunction(name=name, args=args)
|
return CustomFunction(name=name, args=args)
|
||||||
|
|
||||||
|
|
@ -214,12 +214,13 @@ class BuiltInFunction(Function):
|
||||||
|
|
||||||
return f"Expected {self.input_spec.expected_args_str()}.\nReceived {received_args_str}"
|
return f"Expected {self.input_spec.expected_args_str()}.\nReceived {received_args_str}"
|
||||||
|
|
||||||
def __post_init__(self):
|
def validate_args(self) -> "BuiltInFunction":
|
||||||
if not self.input_spec.is_compatible(input_args=self.args):
|
if not self.input_spec.is_compatible(input_args=self.args):
|
||||||
raise StringFormattingException(
|
raise StringFormattingException(
|
||||||
f"Invalid arguments passed to function {self.name}.\n"
|
f"Invalid arguments passed to function {self.name}.\n"
|
||||||
f"{self._expected_received_error_msg()}"
|
f"{self._expected_received_error_msg()}"
|
||||||
)
|
)
|
||||||
|
return self
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def callable(self) -> Callable[..., Resolvable]:
|
def callable(self) -> Callable[..., Resolvable]:
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ from ytdl_sub.script.parser import UNEXPECTED_COMMA_ARGUMENT
|
||||||
from ytdl_sub.script.parser import ArgumentParser
|
from ytdl_sub.script.parser import ArgumentParser
|
||||||
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 ResolvedArray
|
||||||
|
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 Integer
|
from ytdl_sub.script.types.resolvable import Integer
|
||||||
from ytdl_sub.script.types.resolvable import String
|
from ytdl_sub.script.types.resolvable import String
|
||||||
|
|
@ -18,4 +19,40 @@ from ytdl_sub.script.utils.exceptions import InvalidSyntaxException
|
||||||
|
|
||||||
|
|
||||||
class TestFunction:
|
class TestFunction:
|
||||||
pass
|
@pytest.mark.parametrize(
|
||||||
|
"function_str, expected_output",
|
||||||
|
[
|
||||||
|
("{%if(True, True, False)}", True),
|
||||||
|
("{%if(False, True, False)}", False),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_if_function(self, function_str: str, expected_output: bool):
|
||||||
|
assert Script({"func": function_str}).resolve() == {
|
||||||
|
"func": Boolean(expected_output),
|
||||||
|
}
|
||||||
|
|
||||||
|
def test_nested_if_function(self):
|
||||||
|
function_str = """{
|
||||||
|
%if(
|
||||||
|
True,
|
||||||
|
%if(
|
||||||
|
True,
|
||||||
|
%if(
|
||||||
|
True,
|
||||||
|
"winner",
|
||||||
|
True
|
||||||
|
),
|
||||||
|
True
|
||||||
|
),
|
||||||
|
True
|
||||||
|
)
|
||||||
|
}"""
|
||||||
|
assert Script({"func": function_str}).resolve() == {
|
||||||
|
"func": String("winner"),
|
||||||
|
}
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"function_str", ["{%array_at({'a': 'dict?'}, 1)}" "{%array_extend('not', 'array')}"]
|
||||||
|
)
|
||||||
|
def test_incompatible_types(self, function_str):
|
||||||
|
assert Script({"func": function_str}).resolve()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue