TFE_InputTensorHandles InputTFE_InputTensorHandles(
    const py::handle& input_tensors) {
  TFE_InputTensorHandles input_tensor_handles;
  if (input_tensors.ptr() != Py_None) {
    if (!PyList_Check(input_tensors.ptr())) {
      tensorflow::ThrowTypeError("must provide a list of Tensors as inputs");
    }
    Py_ssize_t len = PyList_Size(input_tensors.ptr());
    input_tensor_handles.resize(len);
    for (Py_ssize_t i = 0; i < len; ++i) {
      PyObject* elem = PyList_GetItem(input_tensors.ptr(), i);
      if (!elem) {
        tensorflow::ThrowTypeError("Input Tensor does not exist.");
      }
      if (EagerTensor_CheckExact(elem)) {
        (input_tensor_handles)[i] = EagerTensor_Handle(elem);
      } else if (tensorflow::swig::IsEagerTensorSlow(elem)) {
        // Use equivalent of object.__getattribute__ to get the underlying
        // tf wrapped EagerTensor (if there is one).
        tensorflow::Safe_PyObjectPtr tf_should_use_attr(
#if PY_MAJOR_VERSION < 3
            PyString_InternFromString("_tf_should_use_wrapped_value")
#else
            PyUnicode_InternFromString("_tf_should_use_wrapped_value")
#endif
        );
        tensorflow::Safe_PyObjectPtr value_attr(
            PyObject_GenericGetAttr(elem, tf_should_use_attr.get()));
        if (value_attr) {
          // This is an EagerTensor wrapped inside a TFShouldUse wrapped object.
          (input_tensor_handles)[i] = EagerTensor_Handle(value_attr.get());
        } else {
          // This is a subclass of EagerTensor that we don't support.
          PyErr_Clear();
          tensorflow::ThrowTypeError(
              tensorflow::strings::StrCat(
                  "Saw an object that is an instance of a strict subclass of "
                  "EagerTensor, which is not supported.  Item ",
                  i, " is type: ", elem->ob_type->tp_name)
                  .c_str());
        }
      } else if (tensorflow::swig::IsTensor(elem)) {
        // If it isnt an EagerTensor, but is still a Tensor, it must be a graph
        // tensor.
        tensorflow::Safe_PyObjectPtr name_attr(
            PyObject_GetAttrString(elem, "name"));
        tensorflow::ThrowTypeError(
            tensorflow::strings::StrCat(
                "An op outside of the function building code is being passed\n"
                "a \"Graph\" tensor. It is possible to have Graph tensors\n"
                "leak out of the function building context by including a\n"
                "tf.init_scope in your function building code.\n"
                "For example, the following function will fail:\n",
                "  @tf.function\n", "  def has_init_scope():\n",
                "    my_constant = tf.constant(1.)\n",
                "    with tf.init_scope():\n",
                "      added = my_constant * 2\n",
                "The graph tensor has name: ",
                name_attr ? TFE_GetPythonString(name_attr.get()) : "<unknown>")
                .c_str());
      } else {
        tensorflow::ThrowTypeError(
            tensorflow::strings::StrCat(
                "provided list of inputs contains objects other "
                "than 'EagerTensor'. Item ",
                i, " is type: ", elem->ob_type->tp_name)
                .c_str());
      }
    }
  }
  return input_tensor_handles;
}