code: def _type_check_execution_function_params(
      spec: component_spec.ComponentSpec,
      execution_hook_fn: Optional[Callable[..., Any]] = None,
  ) -> None:
      """Validates execution hook function args with the type check."""
      if execution_hook_fn is None:
          return
  
      channel_parameters = {}
      for parameters in (spec.INPUTS, spec.OUTPUTS):
          channel_parameters.update(parameters)
      signature = inspect.signature(execution_hook_fn)
  
      # Execution function type check.
      for param_name in signature.parameters:
          param_type = signature.parameters[param_name].annotation
          if param_type is inspect.Signature.empty:
              raise TypeError(
                  f'Execution hook function parameter "{param_name}" should be'
                  " annotated."
              )
  
          if param_name in channel_parameters:
              channel = channel_parameters[param_name]
  
              allowed_param_types = [
                  list[channel.type],
                  Optional[channel.type],
              ]
              if not channel.optional:
                  allowed_param_types.append(channel.type)
              # TODO(wssong): We should care for AsyncOutputArtifact type annotation for
              # channels with is_async=True (go/tflex-list-output).
  
              if param_type not in allowed_param_types:
                  raise TypeError(
                      f"Parameter type mismatched {param_name}: {param_type} from the"
                      f" executable function {execution_hook_fn.__name__}. The allowed"
                      f" types are {allowed_param_types}."
                  )
          elif param_name in spec.PARAMETERS:
              exec_prop = spec.PARAMETERS[param_name]
  
              allowed_param_types = [Optional[exec_prop.type]]
              if not exec_prop.optional:
                  allowed_param_types.append(exec_prop.type)
  
              if param_type not in allowed_param_types:
                  raise TypeError(
                      f"Parameter type mismatched {param_name}: {param_type} from the"
                      f" executable function {execution_hook_fn.__name__}. The allowed"
                      f" types are {allowed_param_types}."
                  )
          elif param_type is context.ExecutionContext:
              # Does not validate name to be matched for the ExecutionContext type_hint.
              pass
          else:
              raise AttributeError(
                  f"Unsupported parameter {param_name}: {param_type} from the"
                  f" executable function {execution_hook_fn.__name__}. Parameter should"
                  " be inputs or outputs of the component, or the ExecutionContext"
                  " variable."
              )
  
file_path: tfx/tfx/dsl/component/experimental/component_utils.py
imports: import inspect
  from typing import Any, Callable, Mapping, Optional, Type
  from tfx import types
  from tfx.dsl.component.experimental import utils
  from tfx.dsl.components.base import base_component
  from tfx.dsl.components.base import executor_spec
  from tfx.orchestration.portable.execution import context
  from tfx.proto.orchestration import executable_spec_pb2
  from tfx.types import component_spec
  from tfx.types.system_executions import SystemExecution
  from tfx.utils import name_utils
label_desc: Use image node_id 2 for calling a global function with example usage: _type_check_execution_function_params(spec, execution_hook_fn) without return types