more docs!

This commit is contained in:
Jesse Bannon 2023-12-14 23:09:42 -08:00
parent 720d4e97e4
commit 92961c8f58
8 changed files with 92 additions and 17 deletions

View file

@ -68,6 +68,11 @@ class Functions(
----------
function
A static function whose name will be used as the offered function name.
Raises
------
ValueError
If the name already exists as a function.
"""
if cls.is_built_in(function.__name__):
raise ValueError(

View file

@ -405,6 +405,24 @@ class Script:
resolved: Optional[Dict[str, Resolvable]] = None,
unresolvable: Optional[Set[str]] = None,
) -> Dict[str, Resolvable]:
"""
Given a new set of variable definitions, resolve them using the Script, but do not
add them to the Script itself.
Parameters
----------
variable_definitions
Variables to resolve, but not store in the Script
resolved
Optional. Pre-resolved variables that should be used instead of what is in the script.
unresolvable
Optional. Unresolvable variables that will be ignored in resolution, including all
variables with a dependency to them.
Returns
-------
Dict containing the variable names to their resolved values.
"""
try:
self.add(variable_definitions)
return self._resolve(

View file

@ -93,6 +93,8 @@ class BuiltInFunction(Function, BuiltInFunctionType):
return self
# pylint: disable=missing-raises-doc
@property
def callable(self) -> Callable[..., Resolvable]:
"""
@ -106,6 +108,8 @@ class BuiltInFunction(Function, BuiltInFunctionType):
# Should be validated in the parser
raise UNREACHABLE from exc
# pylint: enable=missing-raises-doc
@functools.cached_property
def function_spec(self) -> FunctionSpec:
"""

View file

@ -114,8 +114,6 @@ class Hashable(Resolvable, ABC):
Resolvable type that can be used as hashes (i.e. in Maps)
"""
pass
@dataclass(frozen=True)
class NonHashable(NamedType, ABC):
@ -123,8 +121,6 @@ class NonHashable(NamedType, ABC):
Type that is known to never be hashable.
"""
pass
@dataclass(frozen=True)
class ResolvableToJson(Resolvable, ABC):
@ -151,32 +147,40 @@ class Numeric(ResolvableT[NumericT], ABC, Generic[NumericT]):
Resolvable numeric types (int/float)
"""
pass
@dataclass(frozen=True)
class Integer(Numeric[int], Argument):
pass
"""
Resolved Integer type
"""
@dataclass(frozen=True)
class Float(Numeric[float], Argument):
pass
"""
Resolved float type
"""
@dataclass(frozen=True)
class Boolean(ResolvableT[bool], Argument):
pass
"""
Resolved bool type
"""
@dataclass(frozen=True)
class String(ResolvableT[str], Argument):
pass
"""
Resolved String type
"""
@dataclass(frozen=True)
class NamedCustomFunction(NamedArgument, ABC):
pass
"""
A custom function with a defined name (but unknown args)
"""
@dataclass(frozen=True)
@ -236,5 +240,3 @@ class LambdaReduce(LambdaTwo):
"""
Type-hinting for functions that apply a reduce-operation using a lambda (two arguments)
"""
pass

View file

@ -17,6 +17,12 @@ class FunctionArgument(Variable):
@classmethod
def from_idx(cls, idx: int, custom_function_name: Optional[str]) -> "FunctionArgument":
"""
Returns
-------
FunctionArgument whose variable name is the index, and optionally contains the custom
function name its defined in as a prefix.
"""
if custom_function_name:
return FunctionArgument(name=f"${custom_function_name}___{idx}", index=idx)
return FunctionArgument(name=f"${idx}", index=idx)

View file

@ -39,7 +39,9 @@ class VariableDependency(ABC):
output.append(arg)
if isinstance(arg, VariableDependency):
# pylint: disable=protected-access
output.extend(arg._recurse_get(ttype))
# pylint: enable=protected-access
return output
@ -83,6 +85,8 @@ class VariableDependency(ABC):
"""
return set(self._recurse_get(Lambda, subclass=True))
# pylint: disable=missing-raises-doc
@final
@property
def custom_functions(self) -> Set[ParsedCustomFunction]:
@ -105,6 +109,8 @@ class VariableDependency(ABC):
return output
# pylint: enable=missing-raises-doc
@abstractmethod
def resolve(
self,

View file

@ -130,11 +130,10 @@ class FunctionArgumentsExceptionFormatter:
for arg in self._input_args:
if isinstance(arg, BuiltInFunctionType):
if is_union(arg.output_type()):
received_type_names.append(
f"%{arg.name}(...)->Union["
f"{', '.join(sorted(type_.type_name() for type_ in arg.output_type().__args__))}"
f"]"
readable_type_names = ", ".join(
sorted(type_.type_name() for type_ in arg.output_type().__args__)
)
received_type_names.append(f"%{arg.name}(...)->Union[{readable_type_names}]")
else:
received_type_names.append(f"%{arg.name}(...)->{arg.output_type().type_name()}")
else:

View file

@ -143,6 +143,11 @@ class FunctionSpec:
return True
def _is_varargs_compatible(self, input_args: List[Argument]) -> bool:
"""
Returns
-------
True if the input args are compatible with the spec's varargs. False otherwise.
"""
assert self.varargs is not None
for input_arg in input_args:
@ -165,22 +170,42 @@ class FunctionSpec:
raise UNREACHABLE # TODO: functions with no args
def is_num_args_compatible(self, num_input_args: int) -> bool:
"""
Returns
-------
True if the number of input args is compatible with the function spec. False otherwise.
"""
if self.args is not None:
return self.num_required_args <= num_input_args <= len(self.args)
return True # varargs can take any number
@property
def num_required_args(self) -> int:
"""
Returns
-------
The minimum number of args required to call the function.
"""
if self.args is not None:
return sum(1 for arg in self.args if not is_optional(arg))
return 0 # varargs can take any number
@property
def is_lambda_reduce_function(self) -> Optional[Type[LambdaReduce]]:
"""
Returns
-------
True if the function is a Lambda-reduce function. False otherwise.
"""
return LambdaReduce if LambdaReduce in (self.args or []) else None
@property
def is_lambda_function(self) -> Optional[Type[Lambda | LambdaTwo | LambdaThree]]:
"""
Returns
-------
True if the function is a Lambda function (excluding reduce). False otherwise.
"""
if LambdaThree in (self.args or []):
return LambdaThree
if LambdaTwo in (self.args or []):
@ -191,6 +216,11 @@ class FunctionSpec:
@property
def is_lambda_like(self) -> Optional[Type[TLambda]]:
"""
Returns
-------
True if the function is a Lambda type (including reduce).
"""
if l_type := self.is_lambda_reduce_function:
return l_type
if l_type := self.is_lambda_function:
@ -199,6 +229,11 @@ class FunctionSpec:
@classmethod
def from_callable(cls, callable_ref: Callable[..., Resolvable]) -> "FunctionSpec":
"""
Returns
-------
FunctionSpec from a built-in function.
"""
arg_spec: FullArgSpec = inspect.getfullargspec(callable_ref)
if arg_spec.varargs:
return FunctionSpec(