linting
This commit is contained in:
parent
96182af2c1
commit
acceb50377
6 changed files with 48 additions and 25 deletions
|
|
@ -222,13 +222,13 @@ class _Parser:
|
||||||
self._set_highlight_position()
|
self._set_highlight_position()
|
||||||
raise NUMERICS_INVALID_CHAR
|
raise NUMERICS_INVALID_CHAR
|
||||||
|
|
||||||
if numeric_string == "." or numeric_string == "-":
|
if numeric_string in (".", "-"):
|
||||||
raise NUMERICS_INVALID_CHAR
|
raise NUMERICS_INVALID_CHAR
|
||||||
|
|
||||||
try:
|
try:
|
||||||
numeric_float = float(numeric_string)
|
numeric_float = float(numeric_string)
|
||||||
except ValueError:
|
except ValueError as exc:
|
||||||
raise UNREACHABLE
|
raise UNREACHABLE from exc
|
||||||
|
|
||||||
if (numeric_int := int(numeric_float)) == numeric_float:
|
if (numeric_int := int(numeric_float)) == numeric_float:
|
||||||
return Integer(value=numeric_int)
|
return Integer(value=numeric_int)
|
||||||
|
|
@ -351,7 +351,7 @@ class _Parser:
|
||||||
if ch == "]":
|
if ch == "]":
|
||||||
self._pos += 1
|
self._pos += 1
|
||||||
return UnresolvedArray(value=function_args)
|
return UnresolvedArray(value=function_args)
|
||||||
else:
|
|
||||||
function_args = self._parse_args(
|
function_args = self._parse_args(
|
||||||
argument_parser=ArgumentParser.ARRAY, breaking_chars="]"
|
argument_parser=ArgumentParser.ARRAY, breaking_chars="]"
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ class Array(NonHashable):
|
||||||
value: List[Resolvable]
|
value: List[Resolvable]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def human_readable_name(cls) -> str:
|
def type_name(cls) -> str:
|
||||||
return "Array"
|
return "Array"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ from ytdl_sub.script.types.resolvable import AnyType_0
|
||||||
from ytdl_sub.script.types.resolvable import AnyType_1
|
from ytdl_sub.script.types.resolvable import AnyType_1
|
||||||
from ytdl_sub.script.types.resolvable import AnyType_2
|
from ytdl_sub.script.types.resolvable import AnyType_2
|
||||||
from ytdl_sub.script.types.resolvable import ArgumentType
|
from ytdl_sub.script.types.resolvable import ArgumentType
|
||||||
|
from ytdl_sub.script.types.resolvable import NamedType
|
||||||
from ytdl_sub.script.types.resolvable import Resolvable
|
from ytdl_sub.script.types.resolvable import Resolvable
|
||||||
from ytdl_sub.script.types.variable import FunctionArgument
|
from ytdl_sub.script.types.variable import FunctionArgument
|
||||||
from ytdl_sub.script.types.variable import Variable
|
from ytdl_sub.script.types.variable import Variable
|
||||||
|
|
@ -30,6 +31,14 @@ def is_union(arg_type: Type) -> bool:
|
||||||
return get_origin(arg_type) is Union
|
return get_origin(arg_type) is Union
|
||||||
|
|
||||||
|
|
||||||
|
def is_optional(arg_type: Type) -> bool:
|
||||||
|
return is_union(arg_type) and type(None) in arg_type.__args__
|
||||||
|
|
||||||
|
|
||||||
|
def get_optional_type(optional_type: Type) -> Type[NamedType]:
|
||||||
|
return [arg for arg in optional_type.__args__ if arg != type(None)][0]
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class FunctionInputSpec:
|
class FunctionInputSpec:
|
||||||
args: Optional[List[Type[Resolvable | Optional[Resolvable]]]] = None
|
args: Optional[List[Type[Resolvable | Optional[Resolvable]]]] = None
|
||||||
|
|
@ -110,10 +119,17 @@ class FunctionInputSpec:
|
||||||
assert False, "should never reach here"
|
assert False, "should never reach here"
|
||||||
|
|
||||||
def expected_args_str(self) -> str:
|
def expected_args_str(self) -> str:
|
||||||
|
def to_human_readable_name(python_type: Type[NamedType] | Type[Union[NamedType]]) -> str:
|
||||||
|
if is_optional(python_type):
|
||||||
|
return f"Optional[{to_human_readable_name(get_optional_type(python_type))}]"
|
||||||
|
if is_union(python_type):
|
||||||
|
return ", ".join(to_human_readable_name(arg) for arg in python_type.__args__)
|
||||||
|
return python_type.type_name()
|
||||||
|
|
||||||
if self.args is not None:
|
if self.args is not None:
|
||||||
return f"({', '.join([type_.__name__ for type_ in self.args])})"
|
return f"({', '.join([to_human_readable_name(type_) for type_ in self.args])})"
|
||||||
elif self.varargs is not None:
|
elif self.varargs is not None:
|
||||||
return f"({self.varargs.__name__}, ...)"
|
return f"({to_human_readable_name(self.varargs.__name__)}, ...)"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_function(cls, func: "BuiltInFunction") -> "FunctionInputSpec":
|
def from_function(cls, func: "BuiltInFunction") -> "FunctionInputSpec":
|
||||||
|
|
@ -210,12 +226,12 @@ class BuiltInFunction(Function):
|
||||||
if is_union(arg.output_type):
|
if is_union(arg.output_type):
|
||||||
# TODO: Move naming to separate function, deal with Union input naming
|
# TODO: Move naming to separate function, deal with Union input naming
|
||||||
received_type_names.append(
|
received_type_names.append(
|
||||||
f"%{arg.name}(...)->Union[{', '.join(arg_type.human_readable_name() for arg_type in arg.output_type.__args__)}]"
|
f"%{arg.name}(...)->Union[{', '.join(arg_type.type_name() for arg_type in arg.output_type.__args__)}]"
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
received_type_names.append(f"%{arg.name}(...)->{arg.output_type.__name__}")
|
received_type_names.append(f"%{arg.name}(...)->{arg.output_type.type_name()}")
|
||||||
else:
|
else:
|
||||||
received_type_names.append(arg.__class__.__name__)
|
received_type_names.append(arg.type_name())
|
||||||
|
|
||||||
received_args_str = f"({', '.join([name for name in received_type_names])})"
|
received_args_str = f"({', '.join([name for name in received_type_names])})"
|
||||||
|
|
||||||
|
|
@ -224,7 +240,7 @@ class BuiltInFunction(Function):
|
||||||
def validate_args(self) -> "BuiltInFunction":
|
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 IncompatibleFunctionArguments(
|
raise IncompatibleFunctionArguments(
|
||||||
f"Invalid arguments passed to function {self.name}.\n"
|
f"Incompatible arguments passed to function {self.name}.\n"
|
||||||
f"{self._expected_received_error_msg()}"
|
f"{self._expected_received_error_msg()}"
|
||||||
)
|
)
|
||||||
return self
|
return self
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ class Map(NonHashable):
|
||||||
value: Dict[Hashable, Resolvable]
|
value: Dict[Hashable, Resolvable]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def human_readable_name(cls) -> str:
|
def type_name(cls) -> str:
|
||||||
return "Map"
|
return "Map"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,25 +10,27 @@ T = TypeVar("T")
|
||||||
NumericT = TypeVar("NumericT", bound=int | float)
|
NumericT = TypeVar("NumericT", bound=int | float)
|
||||||
|
|
||||||
|
|
||||||
class ArgumentType(ABC):
|
class NamedType(ABC):
|
||||||
|
@classmethod
|
||||||
|
def type_name(cls) -> str:
|
||||||
|
return cls.__name__
|
||||||
|
|
||||||
|
|
||||||
|
class ArgumentType(NamedType, ABC):
|
||||||
"""
|
"""
|
||||||
Any possible argument type that has not been resolved yet
|
Any possible argument type that has not been resolved yet
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def human_readable_name(cls) -> str:
|
|
||||||
return cls.__name__
|
|
||||||
|
|
||||||
|
class AnyType_0(NamedType, ABC):
|
||||||
class AnyType_0(ABC):
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AnyType_1(ABC):
|
class AnyType_1(NamedType, ABC):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class AnyType_2(ABC):
|
class AnyType_2(NamedType, ABC):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,8 @@ class TestFunction:
|
||||||
with pytest.raises(
|
with pytest.raises(
|
||||||
IncompatibleFunctionArguments,
|
IncompatibleFunctionArguments,
|
||||||
match=_incompatible_arguments_match(
|
match=_incompatible_arguments_match(
|
||||||
expected="Map, Hashable, Optional", recieved="%if(...)->Union[Map, Array], String"
|
expected="Map, Hashable, Optional[AnyType]",
|
||||||
|
recieved="%if(...)->Union[Map, Array], String",
|
||||||
),
|
),
|
||||||
):
|
):
|
||||||
Script({"func": function_str}).resolve()
|
Script({"func": function_str}).resolve()
|
||||||
|
|
@ -83,4 +84,8 @@ class TestFunction:
|
||||||
"function_str", ["{%array_at({'a': 'dict?'}, 1)}" "{%array_extend('not', 'array')}"]
|
"function_str", ["{%array_at({'a': 'dict?'}, 1)}" "{%array_extend('not', 'array')}"]
|
||||||
)
|
)
|
||||||
def test_incompatible_types(self, function_str):
|
def test_incompatible_types(self, function_str):
|
||||||
assert Script({"func": function_str}).resolve()
|
with pytest.raises(
|
||||||
|
IncompatibleFunctionArguments,
|
||||||
|
match=_incompatible_arguments_match(expected="Array, Integer", recieved="Map, Integer"),
|
||||||
|
):
|
||||||
|
Script({"func": function_str}).resolve()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue