code: def make_attribute(  # pylint: disable=too-many-statements
      key: str, value: Any, doc_string: Optional[str] = None
  ) -> AttributeProto:
      """Makes an AttributeProto based on the value type."""
      attr = AttributeProto()
      attr.name = key
      if doc_string:
          attr.doc_string = doc_string
  
      # Singular cases
      if isinstance(value, numbers.Integral):
          attr.i = int(value)
          attr.type = AttributeProto.INT
      elif isinstance(value, numbers.Real):
          attr.f = float(value)
          attr.type = AttributeProto.FLOAT
      elif isinstance(value, (str, bytes)):
          # Encode strings into utf-8
          attr.s = _to_bytes(value)
          attr.type = AttributeProto.STRING
      elif isinstance(value, TensorProto):
          attr.t.CopyFrom(value)
          attr.type = AttributeProto.TENSOR
      elif isinstance(value, SparseTensorProto):
          attr.sparse_tensor.CopyFrom(value)
          attr.type = AttributeProto.SPARSE_TENSOR
      elif isinstance(value, GraphProto):
          attr.g.CopyFrom(value)
          attr.type = AttributeProto.GRAPH
      elif isinstance(value, TypeProto):
          attr.tp.CopyFrom(value)
          attr.type = AttributeProto.TYPE_PROTO
      # Iterable cases
      elif isinstance(value, collections.abc.Iterable):
          value = list(value)
          types = {type(v) for v in value}
          if all(issubclass(t, numbers.Integral) for t in types):
              attr.ints.extend(value)
              attr.type = AttributeProto.INTS
          elif all(issubclass(t, numbers.Real) for t in types):
              attr.floats.extend(value)
              attr.type = AttributeProto.FLOATS
          elif all(issubclass(t, (str, bytes)) for t in types):
              attr.strings.extend(_to_bytes(v) for v in value)
              attr.type = AttributeProto.STRINGS
          elif all(issubclass(t, TensorProto) for t in types):
              attr.tensors.extend(value)
              attr.type = AttributeProto.TENSORS
          elif all(issubclass(t, SparseTensorProto) for t in types):
              attr.sparse_tensors.extend(value)
              attr.type = AttributeProto.SPARSE_TENSORS
          elif all(issubclass(t, GraphProto) for t in types):
              attr.graphs.extend(value)
              attr.type = AttributeProto.GRAPHS
          elif all(issubclass(t, TypeProto) for t in types):
              attr.type_protos.extend(value)
              attr.type = AttributeProto.TYPE_PROTOS
          else:
              raise ValueError(
                  "Could not infer the attribute type from the elements of the passed Iterable value."
              )
      else:
          raise TypeError(
              f"'{value}' is not an accepted attribute value."
          )
      return attr
  
imports: import collections.abc
  import numbers
  import struct
  from cmath import isnan
  from typing import Any, Callable, Dict, KeysView, List, Optional, Sequence, Tuple, TypeVar, Union, cast
  import google.protobuf.message
  import numpy
  from onnx import IR_VERSION, AttributeProto, FunctionProto, GraphProto, MapProto, ModelProto, NodeProto, OperatorSetIdProto, OptionalProto, SequenceProto, SparseTensorProto, TensorProto, TensorShapeProto, TrainingInfoProto, TypeProto, ValueInfoProto, defs, mapping
label_desc: Use image node_id 21 for calling a global function with example usage: make_attribute(key, value, doc_string) and returns: attr