better type hinting, simplified

This commit is contained in:
Jesse Bannon 2026-01-12 16:42:40 -08:00
parent 25e842d6a6
commit 9b79a78dec
6 changed files with 36 additions and 58 deletions

View file

@ -699,15 +699,11 @@ class Script:
""" """
return set(to_function_definition_name(name) for name in self._functions.keys()) return set(to_function_definition_name(name) for name in self._functions.keys())
def _to_syntax_tree( def _to_syntax_tree(self, maybe_resolved: SyntaxTree | Argument) -> SyntaxTree:
self, maybe_resolved: SyntaxTree | Resolvable | VariableDependency
) -> SyntaxTree:
if isinstance(maybe_resolved, SyntaxTree): if isinstance(maybe_resolved, SyntaxTree):
return maybe_resolved return maybe_resolved
if isinstance(maybe_resolved, (Variable, VariableDependency, Resolvable)):
return SyntaxTree(ast=[maybe_resolved])
return maybe_resolved return SyntaxTree(ast=[maybe_resolved])
def resolve_partial( def resolve_partial(
self, self,
@ -724,22 +720,13 @@ class Script:
ScriptVariableNotResolved ScriptVariableNotResolved
If specifying a filter of variable to resolve, and one of them does not. If specifying a filter of variable to resolve, and one of them does not.
""" """
unresolvable: Set[str] = unresolvable or {}
resolved: Dict[Variable, Resolvable] = {} resolved: Dict[Variable, Resolvable] = {}
unresolved: Dict[Variable, Argument] = {} unresolved: Dict[Variable, Argument] = {
unresolvable: Set[Variable] = {Variable(name) for name in (unresolvable or {})} Variable(name): definition
for name, definition in self._variables.items()
for variable_name, definition in self._variables.items(): if name not in unresolvable
assert len(definition.ast) == 1 }
arg = definition.ast[0]
variable = Variable(variable_name)
if variable in unresolvable:
continue
if isinstance(arg, Resolvable):
resolved[variable] = arg
else:
unresolved[variable] = arg
partially_resolved = True partially_resolved = True
while partially_resolved: while partially_resolved:
@ -749,13 +736,10 @@ class Script:
for variable in list(unresolved.keys()): for variable in list(unresolved.keys()):
definition = unresolved[variable] definition = unresolved[variable]
if isinstance(definition, Variable): maybe_resolved = definition
if definition in unresolvable: if isinstance(definition, Variable) and definition.name not in unresolvable:
maybe_resolved = definition maybe_resolved = resolved.get(definition, unresolved[definition])
else: elif isinstance(definition, VariableDependency):
maybe_resolved = resolved.get(definition, unresolved[definition])
else:
assert isinstance(definition, VariableDependency)
maybe_resolved = definition.partial_resolve( maybe_resolved = definition.partial_resolve(
resolved_variables=resolved, resolved_variables=resolved,
unresolved_variables=unresolved, unresolved_variables=unresolved,
@ -764,8 +748,8 @@ class Script:
if isinstance(maybe_resolved, Resolvable): if isinstance(maybe_resolved, Resolvable):
resolved[variable] = maybe_resolved resolved[variable] = maybe_resolved
partially_resolved = True
del unresolved[variable] del unresolved[variable]
partially_resolved = True
else: else:
unresolved[variable] = maybe_resolved unresolved[variable] = maybe_resolved
@ -774,7 +758,7 @@ class Script:
partially_resolved |= definition != maybe_resolved partially_resolved |= definition != maybe_resolved
return copy.deepcopy(self).add_parsed( return copy.deepcopy(self).add_parsed(
{var.name: self._variables[var.name] for var in unresolvable} {var_name: self._variables[var_name] for var_name in unresolvable}
| {var.name: self._to_syntax_tree(definition) for var, definition in resolved.items()} | {var.name: self._to_syntax_tree(definition) for var, definition in resolved.items()}
| {var.name: self._to_syntax_tree(definition) for var, definition in unresolved.items()} | {var.name: self._to_syntax_tree(definition) for var, definition in unresolved.items()}
) )

View file

@ -11,7 +11,6 @@ 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
from ytdl_sub.script.types.variable import Variable from ytdl_sub.script.types.variable import Variable
from ytdl_sub.script.types.variable_dependency import TypeT
from ytdl_sub.script.types.variable_dependency import VariableDependency from ytdl_sub.script.types.variable_dependency import VariableDependency
@ -49,11 +48,11 @@ class UnresolvedArray(_Array, VariableDependency, FutureResolvable):
) )
def partial_resolve( def partial_resolve(
self: TypeT, self,
resolved_variables: Dict[Variable, Resolvable], resolved_variables: Dict[Variable, Resolvable],
unresolved_variables: Dict[Variable, Argument], unresolved_variables: Dict[Variable, Argument],
custom_functions: Dict[str, "VariableDependency"], custom_functions: Dict[str, VariableDependency],
) -> TypeT | Resolvable: ) -> Argument | Resolvable:
maybe_resolvable_values, is_resolvable = VariableDependency.try_partial_resolve( maybe_resolvable_values, is_resolvable = VariableDependency.try_partial_resolve(
args=self.value, args=self.value,
resolved_variables=resolved_variables, resolved_variables=resolved_variables,

View file

@ -24,7 +24,6 @@ from ytdl_sub.script.types.resolvable import ReturnableArgumentA
from ytdl_sub.script.types.resolvable import ReturnableArgumentB from ytdl_sub.script.types.resolvable import ReturnableArgumentB
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
from ytdl_sub.script.types.variable_dependency import TypeT
from ytdl_sub.script.types.variable_dependency import VariableDependency from ytdl_sub.script.types.variable_dependency import VariableDependency
from ytdl_sub.script.utils.exception_formatters import FunctionArgumentsExceptionFormatter from ytdl_sub.script.utils.exception_formatters import FunctionArgumentsExceptionFormatter
from ytdl_sub.script.utils.exceptions import UNREACHABLE from ytdl_sub.script.utils.exceptions import UNREACHABLE
@ -91,8 +90,8 @@ class CustomFunction(Function, NamedCustomFunction):
self, self,
resolved_variables: Dict[Variable, Resolvable], resolved_variables: Dict[Variable, Resolvable],
unresolved_variables: Dict[Variable, Argument], unresolved_variables: Dict[Variable, Argument],
custom_functions: Dict[str, "VariableDependency"], custom_functions: Dict[str, VariableDependency],
) -> TypeT | Resolvable: ) -> Argument | Resolvable:
maybe_resolvable_args, _ = VariableDependency.try_partial_resolve( maybe_resolvable_args, _ = VariableDependency.try_partial_resolve(
args=self.args, args=self.args,
resolved_variables=resolved_variables, resolved_variables=resolved_variables,
@ -445,8 +444,8 @@ class BuiltInFunction(Function, BuiltInFunctionType):
self, self,
resolved_variables: Dict[Variable, Resolvable], resolved_variables: Dict[Variable, Resolvable],
unresolved_variables: Dict[Variable, Argument], unresolved_variables: Dict[Variable, Argument],
custom_functions: Dict[str, "VariableDependency"], custom_functions: Dict[str, VariableDependency],
) -> TypeT | Resolvable: ) -> Argument | Resolvable:
conditional_return_args = self.function_spec.conditional_arg_indices( conditional_return_args = self.function_spec.conditional_arg_indices(
num_input_args=len(self.args) num_input_args=len(self.args)
) )

View file

@ -13,7 +13,6 @@ 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
from ytdl_sub.script.types.variable import Variable from ytdl_sub.script.types.variable import Variable
from ytdl_sub.script.types.variable_dependency import TypeT
from ytdl_sub.script.types.variable_dependency import VariableDependency from ytdl_sub.script.types.variable_dependency import VariableDependency
from ytdl_sub.script.utils.exceptions import KeyNotHashableRuntimeException from ytdl_sub.script.utils.exceptions import KeyNotHashableRuntimeException
@ -57,11 +56,11 @@ class UnresolvedMap(_Map, VariableDependency, FutureResolvable):
return Map(output) return Map(output)
def partial_resolve( def partial_resolve(
self: TypeT, self,
resolved_variables: Dict[Variable, Resolvable], resolved_variables: Dict[Variable, Resolvable],
unresolved_variables: Dict[Variable, Argument], unresolved_variables: Dict[Variable, Argument],
custom_functions: Dict[str, "VariableDependency"], custom_functions: Dict[str, VariableDependency],
) -> TypeT | Resolvable: ) -> Argument | Resolvable:
maybe_resolvable_keys, is_keys_resolvable = VariableDependency.try_partial_resolve( maybe_resolvable_keys, is_keys_resolvable = VariableDependency.try_partial_resolve(
args=self.value.keys(), args=self.value.keys(),
resolved_variables=resolved_variables, resolved_variables=resolved_variables,

View file

@ -3,11 +3,11 @@ from typing import Dict
from typing import List from typing import List
from typing import Optional from typing import Optional
from ytdl_sub.script.types.function import BuiltInFunction
from ytdl_sub.script.types.resolvable import Argument from ytdl_sub.script.types.resolvable import Argument
from ytdl_sub.script.types.resolvable import Resolvable from ytdl_sub.script.types.resolvable import Resolvable
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.script.types.variable_dependency import TypeT
from ytdl_sub.script.types.variable_dependency import VariableDependency from ytdl_sub.script.types.variable_dependency import VariableDependency
@ -42,25 +42,22 @@ class SyntaxTree(VariableDependency):
return String("".join([str(res) for res in resolved])) return String("".join([str(res) for res in resolved]))
def partial_resolve( def partial_resolve(
self: TypeT, self,
resolved_variables: Dict[Variable, Resolvable], resolved_variables: Dict[Variable, Resolvable],
unresolved_variables: Dict[Variable, Argument], unresolved_variables: Dict[Variable, Argument],
custom_functions: Dict[str, VariableDependency], custom_functions: Dict[str, VariableDependency],
) -> TypeT | Resolvable: ) -> Argument | Resolvable:
maybe_resolvable_values, is_resolvable = VariableDependency.try_partial_resolve( maybe_resolvable_values, _ = VariableDependency.try_partial_resolve(
args=self.ast, args=self.ast,
resolved_variables=resolved_variables, resolved_variables=resolved_variables,
unresolved_variables=unresolved_variables, unresolved_variables=unresolved_variables,
custom_functions=custom_functions, custom_functions=custom_functions,
) )
if is_resolvable: if len(maybe_resolvable_values) > 1:
return self.resolve( return BuiltInFunction(name="concat", args=maybe_resolvable_values)
resolved_variables=resolved_variables,
custom_functions=custom_functions,
)
return SyntaxTree(ast=maybe_resolvable_values) return maybe_resolvable_values[0]
@property @property
def maybe_resolvable(self) -> Optional[Resolvable]: def maybe_resolvable(self) -> Optional[Resolvable]:
@ -100,9 +97,9 @@ class ResolvedSyntaxTree(SyntaxTree):
return self.ast[0] return self.ast[0]
def partial_resolve( def partial_resolve(
self: TypeT, self,
resolved_variables: Dict[Variable, Resolvable], resolved_variables: Dict[Variable, Resolvable],
unresolved_variables: Dict[Variable, Argument], unresolved_variables: Dict[Variable, Argument],
custom_functions: Dict[str, VariableDependency], custom_functions: Dict[str, VariableDependency],
) -> TypeT | Resolvable: ) -> Argument | Resolvable:
return self.ast[0] return self.ast[0]

View file

@ -141,11 +141,11 @@ class VariableDependency(ABC):
@abstractmethod @abstractmethod
def partial_resolve( def partial_resolve(
self: TypeT, self,
resolved_variables: Dict[Variable, Resolvable], resolved_variables: Dict[Variable, Resolvable],
unresolved_variables: Dict[Variable, Argument], unresolved_variables: Dict[Variable, Argument],
custom_functions: Dict[str, "VariableDependency"], custom_functions: Dict[str, "VariableDependency"],
) -> TypeT | Resolvable: ) -> Argument | Resolvable:
""" """
Parameters Parameters
---------- ----------
@ -258,7 +258,7 @@ class VariableDependency(ABC):
Attempts to resolve a list of arguments. Returns a tuple of them post partially resolved, Attempts to resolve a list of arguments. Returns a tuple of them post partially resolved,
and a boolean indicating whether all of them are fully resolved. and a boolean indicating whether all of them are fully resolved.
""" """
maybe_resolvable_args: List[Resolvable | Argument] = [] maybe_resolvable_args: List[Resolvable | Argument | "VariableDependency"] = []
is_resolvable = True is_resolvable = True
for arg in args: for arg in args:
if isinstance(arg, Lambda) and arg.value in custom_functions: if isinstance(arg, Lambda) and arg.value in custom_functions: