class_docstr: A specification of inputs, outputs, parameters, annotation for a component.
  
  Components should have a corresponding ComponentSpec inheriting from this
  class and must override:
  
    - PARAMETERS (as a dict of string keys and ExecutionParameter values),
    - INPUTS (as a dict of string keys and ChannelParameter values),
    - OUTPUTS (also a dict of string keys and ChannelParameter values) and
    - TYPE_ANNOTATION (execution annotations from
    tfx.v1.dsl.standard_annotations)
  
  Here is an example of how a ComponentSpec may be defined:
  
  ```python
  from tfx import v1 as tfx
  
  class MyCustomComponentSpec(ComponentSpec):
    PARAMETERS = {
        'internal_option': ExecutionParameter(type=str),
    }
    INPUTS = {
        'input_examples': ChannelParameter(type=standard_artifacts.Examples),
    }
    OUTPUTS = {
        'output_examples': ChannelParameter(type=standard_artifacts.Examples),
    }
    TYPE_ANNOTATION = tfx.dsl.standard_annotations.Train
  ```
  
  To create an instance of a subclass, call it directly with any execution
  parameters / inputs / outputs as kwargs.  For example:
  
  spec = MyCustomComponentSpec(
      internal_option='abc',
      input_examples=input_examples_channel,
      output_examples=output_examples_channel)
  
  Attributes:
    PARAMETERS: a dict of string keys and ExecutionParameter values.
    INPUTS: a dict of string keys and ChannelParameter values.
    OUTPUTS: a dict of string keys and ChannelParameter values.
    TYPE_ANNOTATION: an execution annotations from
      tfx.v1.dsl.standard_annotations.
docstr: Check the parameters and types passed to this ComponentSpec.
code: def _validate(cls):
      """Check the parameters and types passed to this ComponentSpec."""
      for param_name in ("PARAMETERS", "INPUTS", "OUTPUTS"):
          if not hasattr(cls, param_name):
              raise TypeError(f"{cls} does not have {param_name}.")
          param = getattr(cls, param_name)
          if not isinstance(param, Mapping):
              raise TypeError(
                  f"{cls}.{param_name} should be a dict but got {param} instead."
              )
  
      # Validate that the ComponentSpec class is well-formed.
      seen_arg_names = set()
      for arg_name in itertools.chain(
          cls.PARAMETERS, cls.INPUTS, cls.OUTPUTS
      ):
          if arg_name in seen_arg_names:
              raise ValueError(
                  (
                      "The ComponentSpec subclass %s has a duplicate argument with "
                      "name %s. Argument names should be unique across the PARAMETERS, "
                      "INPUTS and OUTPUTS dicts."
                  )
                  % (cls.__class__, arg_name)
              )
          seen_arg_names.add(arg_name)
  
      for arg in cls.PARAMETERS.values():
          if not isinstance(arg, ExecutionParameter):
              raise TypeError(
                  (
                      "PARAMETERS dict expects values of type ExecutionParameter, "
                      "got {}."
                  ).format(arg)
              )
  
      for arg in itertools.chain(
          cls.INPUTS.values(), cls.OUTPUTS.values()
      ):
          if not isinstance(arg, ChannelParameter):
              raise TypeError(
                  (
                      "INPUTS and OUTPUTS dicts expect values of type ChannelParameter, "
                      " got {}."
                  ).format(arg)
              )
  
      for arg_name, arg in cls.OUTPUTS.items():
          if arg.allow_empty_explicitly_set:
              raise TypeError(
                  "Output channels should not explicitly set allow_empty, but output "
                  "channel %s did." % arg_name
              )
  
imports: import copy
  import inspect
  import itertools
  from typing import Any, Dict, List, Mapping, Optional, Type, cast
  from tfx.dsl.component.experimental.json_compat import check_strict_json_compat
  from tfx.dsl.placeholder import placeholder
  from tfx.types import artifact
  from tfx.types import channel
  from tfx.types.system_executions import SystemExecution
  from tfx.utils import json_utils
  from tfx.utils import proto_utils
  from google.protobuf import message
label_desc: Use image node_id 4 for calling the ComponentSpec obj's underlying member method code with example usage: obj._validate(cls) without return types