if now uses psuedo generics

This commit is contained in:
Jesse Bannon 2023-11-06 23:47:03 -08:00
parent b371a29500
commit 2bf4f01b8d
7 changed files with 49 additions and 38 deletions

View file

@ -1,8 +1,9 @@
from typing import Optional from typing import Optional
from ytdl_sub.script.functions.numeric_functions import NumericFunctions from ytdl_sub.script.functions.numeric_functions import NumericFunctions
from ytdl_sub.script.functions.special_functions import SpecialFunctions
from ytdl_sub.script.functions.string_functions import StringFunctions from ytdl_sub.script.functions.string_functions import StringFunctions
class Functions(StringFunctions, NumericFunctions): class Functions(StringFunctions, NumericFunctions, SpecialFunctions):
pass pass

View file

@ -1,10 +1,16 @@
from typing import Union
from ytdl_sub.script.types.resolvable import Boolean from ytdl_sub.script.types.resolvable import Boolean
from ytdl_sub.script.types.resolvable import Resolvable from ytdl_sub.script.types.resolvable import Resolvable
from ytdl_sub.script.types.resolvable import Resolvable_1
from ytdl_sub.script.types.resolvable import Resolvable_2
class SpecialFunctions: class SpecialFunctions:
@staticmethod @staticmethod
def if_(condition: Boolean, true: Resolvable, false: Resolvable) -> Resolvable: def if_(
condition: Boolean, true: Resolvable, false: Resolvable
) -> Union[Resolvable_1, Resolvable_2]:
if condition.value: if condition.value:
return true return true
return false return false

View file

@ -4,7 +4,6 @@ from typing import Optional
from ytdl_sub.script.syntax_tree import SyntaxTree from ytdl_sub.script.syntax_tree import SyntaxTree
from ytdl_sub.script.types.function import ArgumentType from ytdl_sub.script.types.function import ArgumentType
from ytdl_sub.script.types.function import Function from ytdl_sub.script.types.function import Function
from ytdl_sub.script.types.function import IfFunction
from ytdl_sub.script.types.resolvable import Boolean 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
@ -158,10 +157,6 @@ class _Parser:
while ch := self._read(): while ch := self._read():
if ch == ")": if ch == ")":
# Special case for If functions since it can return a Union based on input types
if function_name == "if":
return IfFunction(name=function_name, args=function_args)
return Function(name=function_name, args=function_args) return Function(name=function_name, args=function_args)
if ch != "(": if ch != "(":

View file

@ -20,6 +20,9 @@ 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 Resolvable from ytdl_sub.script.types.resolvable import Resolvable
from ytdl_sub.script.types.resolvable import Resolvable_0
from ytdl_sub.script.types.resolvable import Resolvable_1
from ytdl_sub.script.types.resolvable import Resolvable_2
from ytdl_sub.script.types.resolvable import String from ytdl_sub.script.types.resolvable import String
from ytdl_sub.script.types.variable import Variable from ytdl_sub.script.types.variable import Variable
from ytdl_sub.utils.exceptions import StringFormattingException from ytdl_sub.utils.exceptions import StringFormattingException
@ -173,10 +176,12 @@ class Function(VariableDependency):
@property @property
def callable(self) -> Callable[..., Resolvable]: def callable(self) -> Callable[..., Resolvable]:
try: if hasattr(Functions, self.name):
return getattr(Functions, self.name) return getattr(Functions, self.name)
except AttributeError: if hasattr(Functions, self.name + "_"):
raise StringFormattingException(f"Function name {self.name} does not exist") return getattr(Functions, self.name + "_")
raise StringFormattingException(f"Function name {self.name} does not exist")
@functools.cached_property @functools.cached_property
def arg_spec(self) -> FullArgSpec: def arg_spec(self) -> FullArgSpec:
@ -188,7 +193,22 @@ class Function(VariableDependency):
@property @property
def output_type(self) -> Type[Resolvable]: def output_type(self) -> Type[Resolvable]:
return self.arg_spec.annotations["return"] output_type = self.arg_spec.annotations["return"]
if is_union(output_type):
union_types_list = []
for union_type in output_type.__args__:
if union_type == Resolvable_0:
union_types_list.append(type(self.args[0]))
elif union_type == Resolvable_1:
union_types_list.append(type(self.args[1]))
elif union_type == Resolvable_2:
union_types_list.append(type(self.args[2]))
else:
union_types_list.append(union_type)
return Union[tuple(union_types_list)]
return output_type
@property @property
def variables(self) -> Set[Variable]: def variables(self) -> Set[Variable]:
@ -208,18 +228,3 @@ class Function(VariableDependency):
def resolve(self, resolved_variables: Dict[Variable, Resolvable]) -> Resolvable: def resolve(self, resolved_variables: Dict[Variable, Resolvable]) -> Resolvable:
raise NotImplemented() raise NotImplemented()
@dataclass(frozen=True)
class IfFunction(Function):
def __post_init__(self):
super().__post_init__()
assert len(self.args) == 3 # bool, true, false
@property
def callable(self) -> Callable[..., Resolvable]:
return SpecialFunctions.if_
@property
def output_type(self) -> Type[Resolvable]:
return Union[self.args[1].__class__, self.args[2].__class__]

View file

@ -10,8 +10,20 @@ T = TypeVar("T")
NumericT = TypeVar("NumericT", bound=int | float) NumericT = TypeVar("NumericT", bound=int | float)
class Resolvable_0(ABC):
pass
class Resolvable_1(ABC):
pass
class Resolvable_2(ABC):
pass
@dataclass(frozen=True) @dataclass(frozen=True)
class Resolvable(ABC): class Resolvable(Resolvable_0, Resolvable_1, Resolvable_2, ABC):
value: Any value: Any
def __str__(self) -> str: def __str__(self) -> str:

View file

@ -5,7 +5,6 @@ import pytest
from ytdl_sub.script.parser import parse from ytdl_sub.script.parser import parse
from ytdl_sub.script.syntax_tree import SyntaxTree from ytdl_sub.script.syntax_tree import SyntaxTree
from ytdl_sub.script.types.function import Function from ytdl_sub.script.types.function import Function
from ytdl_sub.script.types.function import IfFunction
from ytdl_sub.script.types.resolvable import Boolean 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
@ -34,7 +33,7 @@ class TestParser:
assert parsed == SyntaxTree( assert parsed == SyntaxTree(
[ [
String("hello "), String("hello "),
IfFunction( Function(
name="if", args=[Boolean(value=True), String(value="hi"), Float(value=3.4)] name="if", args=[Boolean(value=True), String(value="hi"), Float(value=3.4)]
), ),
] ]
@ -49,7 +48,7 @@ class TestParser:
Function( Function(
name="concat", name="concat",
args=[ args=[
IfFunction( Function(
name="if", args=[Boolean(value=True), String("hi"), String("mom")] name="if", args=[Boolean(value=True), String("hi"), String("mom")]
), ),
String(value="and dad"), String(value="and dad"),
@ -66,7 +65,7 @@ class TestParser:
Function( Function(
name="string", name="string",
args=[ args=[
IfFunction(name="if", args=[Boolean(True), String("hi"), Integer(4)]), Function(name="if", args=[Boolean(True), String("hi"), Integer(4)]),
], ],
), ),
] ]

View file

@ -1,15 +1,8 @@
from typing import Dict from typing import Dict
from typing import Union
import pytest import pytest
from ytdl_sub.script.parser import parse
from ytdl_sub.script.syntax_tree import SyntaxTree from ytdl_sub.script.syntax_tree import SyntaxTree
from ytdl_sub.script.types.function import Function
from ytdl_sub.script.types.function import IfFunction
from ytdl_sub.script.types.resolvable import Boolean
from ytdl_sub.script.types.resolvable import Float
from ytdl_sub.script.types.resolvable import Integer
from ytdl_sub.script.types.resolvable import String from ytdl_sub.script.types.resolvable import String
from ytdl_sub.script.types.variable import Variable from ytdl_sub.script.types.variable import Variable
from ytdl_sub.utils.exceptions import StringFormattingException from ytdl_sub.utils.exceptions import StringFormattingException