Source code for symforce.type_helpers

# ----------------------------------------------------------------------------
# SymForce - Copyright 2022, Skydio, Inc.
# This source code is under the Apache 2.0 license found in the LICENSE file.
# ----------------------------------------------------------------------------

import inspect

from symforce import ops
from symforce import python_util
from symforce import typing as T
from symforce.values import Values


[docs]def deduce_input_type( parameter: inspect.Parameter, func: T.Callable, is_first_parameter: bool ) -> T.ElementOrType: """ Attempt to deduce the type of an input parameter to a function Strategy: 1) If it's annotated with something, return that 2) If it's the first parameter and its name is "self", search for a type by the class part of the function's qualified name """ annotation = parameter.annotation # 1) if annotation is not parameter.empty: return T.get_type_hints(python_util.get_func_from_maybe_bound_function(func))[ parameter.name ] # 2) if is_first_parameter and parameter.name == "self": # self is unannotated, so try setting the annotation to the class name # __qualname__ should be of the form Class.func_name return python_util.get_class_for_method(func) raise ValueError( f'Type for argument "{parameter.name}" to {func} could not be deduced.' + " Please either provide input_types or add a type annotation" )
[docs]def deduce_input_types(func: T.Callable) -> T.Sequence[T.ElementOrType]: """ Attempt to deduce input types from the type annotations on func, to be used by :meth:`Codegen.function <symforce.codegen.codegen.Codegen.function>`. See the docstring on :func:`deduce_input_type` for deduction strategy """ signature = inspect.signature(func) input_types = [] for i, parameter in enumerate(signature.parameters.values()): input_types.append(deduce_input_type(parameter, func, i == 0)) return input_types
[docs]def symbolic_inputs( func: T.Callable, input_types: T.Optional[T.Sequence[T.ElementOrType]] = None ) -> Values: """ Return symbolic arguments for the inputs to ``func`` Args: func: A callable; args should have type annotations, and those types should be constructible automatically with :meth:`symforce.ops.storage_ops.StorageOps.symbolic` Returns: A tuple with a symbolic object for each input to func See also: :func:`sf.util.symbolic_eval <symforce.util.symbolic_eval>` """ parameters = [ p for p in inspect.signature(func).parameters.values() if p.kind in {inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD} ] if input_types is None: input_types = deduce_input_types(func) else: assert len(parameters) == len( input_types ), f"Parameters: {parameters}, inputs_types: {input_types}" # Formulate symbolic arguments to function inputs = Values() for arg_parameter, arg_type in zip(parameters, input_types): inputs[arg_parameter.name] = ops.StorageOps.symbolic(arg_type, arg_parameter.name) return inputs