From 879c0701940cea00da4a791f20e4c01267aad70e Mon Sep 17 00:00:00 2001 From: Jesse Bannon Date: Sat, 18 Nov 2023 00:40:54 -0800 Subject: [PATCH] better function subclasses --- src/ytdl_sub/script/types/function.py | 10 ++++------ src/ytdl_sub/script/types/resolvable.py | 6 +++++- src/ytdl_sub/script/utils/exception_formatters.py | 6 +++--- src/ytdl_sub/script/utils/type_checking.py | 4 ++-- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/ytdl_sub/script/types/function.py b/src/ytdl_sub/script/types/function.py index 1247cfe7..3e01bcee 100644 --- a/src/ytdl_sub/script/types/function.py +++ b/src/ytdl_sub/script/types/function.py @@ -16,8 +16,9 @@ from ytdl_sub.script.types.resolvable import AnyTypeReturnable from ytdl_sub.script.types.resolvable import AnyTypeReturnableA from ytdl_sub.script.types.resolvable import AnyTypeReturnableB from ytdl_sub.script.types.resolvable import ArgumentType -from ytdl_sub.script.types.resolvable import FunctionLike +from ytdl_sub.script.types.resolvable import FunctionType from ytdl_sub.script.types.resolvable import Resolvable +from ytdl_sub.script.types.resolvable import TypeHintedFunctionType from ytdl_sub.script.types.variable import FunctionArgument from ytdl_sub.script.types.variable import Variable from ytdl_sub.script.types.variable_dependency import VariableDependency @@ -28,10 +29,7 @@ from ytdl_sub.utils.exceptions import StringFormattingException @dataclass(frozen=True) -class Function(VariableDependency, ArgumentType, ABC): - name: str - args: List[ArgumentType] - +class Function(FunctionType, VariableDependency, ABC): @property def variables(self) -> Set[Variable]: """ @@ -104,7 +102,7 @@ class CustomFunction(Function): raise StringFormattingException(f"Custom function {self.name} does not exist") -class BuiltInFunction(Function, FunctionLike): +class BuiltInFunction(Function, TypeHintedFunctionType): def validate_args(self) -> "BuiltInFunction": if not self.input_spec.is_compatible(input_args=self.args): raise FunctionArgumentsExceptionFormatter( diff --git a/src/ytdl_sub/script/types/resolvable.py b/src/ytdl_sub/script/types/resolvable.py index fa1a0253..cb0538d3 100644 --- a/src/ytdl_sub/script/types/resolvable.py +++ b/src/ytdl_sub/script/types/resolvable.py @@ -116,10 +116,14 @@ class String(ResolvableT[str], Hashable, ArgumentType): pass -class FunctionLike(NamedType): +@dataclass(frozen=True) +class FunctionType(ArgumentType, ABC): name: str args: List[ArgumentType] + +@dataclass(frozen=True) +class TypeHintedFunctionType(FunctionType, ABC): @abstractmethod def output_type(self) -> Type[Resolvable]: pass diff --git a/src/ytdl_sub/script/utils/exception_formatters.py b/src/ytdl_sub/script/utils/exception_formatters.py index 268d1063..1cda2578 100644 --- a/src/ytdl_sub/script/utils/exception_formatters.py +++ b/src/ytdl_sub/script/utils/exception_formatters.py @@ -4,8 +4,8 @@ from typing import Type from typing import TypeVar from typing import Union -from ytdl_sub.script.types.resolvable import FunctionLike from ytdl_sub.script.types.resolvable import NamedType +from ytdl_sub.script.types.resolvable import TypeHintedFunctionType from ytdl_sub.script.utils.exceptions import IncompatibleFunctionArguments from ytdl_sub.script.utils.exceptions import UserException from ytdl_sub.script.utils.type_checking import FunctionInputSpec @@ -90,7 +90,7 @@ class FunctionArgumentsExceptionFormatter: def __init__( self, input_spec: FunctionInputSpec, - function_instance: FunctionLike, + function_instance: TypeHintedFunctionType, ): self._args = input_spec.args self._varargs = input_spec.varargs @@ -115,7 +115,7 @@ class FunctionArgumentsExceptionFormatter: def highlight(self) -> IncompatibleFunctionArguments: received_type_names: List[str] = [] for arg in self._input_args: - if isinstance(arg, FunctionLike): + if isinstance(arg, TypeHintedFunctionType): if is_union(arg.output_type()): # TODO: Move naming to separate function, deal with Union input naming received_type_names.append( diff --git a/src/ytdl_sub/script/utils/type_checking.py b/src/ytdl_sub/script/utils/type_checking.py index a02910eb..1e3bcd91 100644 --- a/src/ytdl_sub/script/utils/type_checking.py +++ b/src/ytdl_sub/script/utils/type_checking.py @@ -6,7 +6,7 @@ from typing import Union from typing import get_origin from ytdl_sub.script.types.resolvable import ArgumentType -from ytdl_sub.script.types.resolvable import FunctionLike +from ytdl_sub.script.types.resolvable import FunctionType from ytdl_sub.script.types.resolvable import NamedType from ytdl_sub.script.types.resolvable import Resolvable from ytdl_sub.script.types.variable import Variable @@ -30,7 +30,7 @@ def is_type_compatible( expected_arg_type: Type[Resolvable | Optional[Resolvable]], ) -> bool: arg_type: Type[NamedType] = arg.__class__ - if isinstance(arg, FunctionLike): + if isinstance(arg, FunctionType): arg_type = arg.output_type() elif isinstance(arg, Variable): return True # unresolved variables can be anything, so pass for now