tensorflow/python/lib/core/py_func.cc
// Calls the registered py function through the trampoline.
Calls the registered py function through the trampoline.
Calls the registered py function through the trampoline .
Status DoCallPyFunc(PyCall* call, bool* out_log_on_error) {
  *out_log_on_error = true;
  PyObject* trampoline = GetPyTrampoline();
  if (trampoline == nullptr) {
    return errors::InvalidArgument(
        "Missing py trampoline. Most likely, it is a link error.");
  }
  PyObject* args = nullptr;
  std::unique_ptr<EagerExecutor> new_executor = nullptr;
  EagerExecutor* old_executor = nullptr;
  if (call->eager) {
    TFE_Context* ctx = reinterpret_cast<TFE_Context*>(PyCapsule_GetPointer(
        PyObject_GetAttrString(trampoline, "_ctx"), nullptr));
    CHECK_NE(ctx, nullptr);
    TF_RETURN_IF_ERROR(MakeArgTuple(call, ctx, &args));
    new_executor.reset(new EagerExecutor(call->eager_async));
    old_executor = &(tensorflow::unwrap(ctx)->Executor());
    tensorflow::unwrap(ctx)->SetExecutorForThread(new_executor.get());
  } else {
    TF_RETURN_IF_ERROR(MakeArgTuple(call, nullptr, &args));
  }
  CHECK(args);
  PyObject* result = PyEval_CallObject(trampoline, args);
  Py_DECREF(args);
  Status s = Status::OK();
  if (result == nullptr) {
    if (PyErr_Occurred()) {
      if (PyErr_ExceptionMatches(PyExc_ValueError) ||
          PyErr_ExceptionMatches(PyExc_TypeError)) {
        s = errors::InvalidArgument(PyExceptionFetch());
      } else if (PyErr_ExceptionMatches(PyExc_StopIteration)) {
        *out_log_on_error = false;
        s = errors::OutOfRange(PyExceptionFetch());
      } else if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
        s = errors::ResourceExhausted(PyExceptionFetch());
      } else if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) {
        s = errors::Unimplemented(PyExceptionFetch());
      } else {
        s = errors::Unknown(PyExceptionFetch());
      }
    } else {
      s = errors::Internal("Failed to run py callback ", call->token,
                           ": see error log.");
    }
  }
  TFE_Context* ctx = reinterpret_cast<TFE_Context*>(PyCapsule_GetPointer(
      PyObject_GetAttrString(trampoline, "_ctx"), nullptr));
  if (new_executor != nullptr) {
    s.Update(new_executor->WaitForAllPendingNodes());
    tensorflow::unwrap(ctx)->SetExecutorForThread(old_executor);
  }
  TF_RETURN_IF_ERROR(s);
  if (PyList_Check(result)) {
    call->out.clear();
    for (int i = 0; i < PyList_Size(result); ++i) {
      Tensor t;
      if (call->eager) {
        const PyObject* item = PyList_GetItem(result, i);
        if (EagerTensor_CheckExact(item)) {
          const Tensor* tensor = nullptr;
          s = ExtractTensorFromEagerTensor(item, ctx, call->device, &tensor);
          if (s.ok()) t = *tensor;
        } else {
          s = errors::FailedPrecondition(
              "Expected EagerTensor, found PyObject of type: ",
              Py_TYPE(item)->tp_name);
        }
      } else {
        s = NdarrayToTensor(PyList_GetItem(result, i), &t);
      }
      if (!s.ok()) {
        break;
      }
      call->out.push_back(t);
    }
  } else if (EagerTensor_CheckExact(result) || result == Py_None) {
    DCHECK(call->eager);
    if (result != Py_None) {
      const Tensor* t = nullptr;
      s = ExtractTensorFromEagerTensor(result, ctx, call->device, &t);
      if (s.ok()) call->out.push_back(*t);
    }
  } else if (PyArray_Check(result)) {
    DCHECK(!call->eager);
    if (!IsSingleNone(result)) {
      Tensor t;
      s = NdarrayToTensor(result, &t);
      if (s.ok()) {
        call->out.push_back(t);
      }
    }
  } else {
    s = errors::Internal("Unexpected PyObject was returned: ",
                         Py_TYPE(result)->tp_name);
  }
  Py_DECREF(result);
  return s;
}
Status DoCallPyFunc ( PyCall * call , bool * out_log_on_error ) { * out_log_on_error = true ; PyObject * trampoline = GetPyTrampoline ( ) ; if ( trampoline == nullptr ) { return errors :: InvalidArgument ( " " ) ; } PyObject * args = nullptr ; std :: unique_ptr < EagerExecutor > new_executor = nullptr ; EagerExecutor * old_executor = nullptr ; if ( call -> eager ) { TFE_Context * ctx = reinterpret_cast < TFE_Context * > ( PyCapsule_GetPointer ( PyObject_GetAttrString ( trampoline , " " ) , nullptr ) ) ; CHECK_NE ( ctx , nullptr ) ; TF_RETURN_IF_ERROR ( MakeArgTuple ( call , ctx , & args ) ) ; new_executor . reset ( new EagerExecutor ( call -> eager_async ) ) ; old_executor = & ( tensorflow :: unwrap ( ctx ) -> Executor ( ) ) ; tensorflow :: unwrap ( ctx ) -> SetExecutorForThread ( new_executor . get ( ) ) ; } else { TF_RETURN_IF_ERROR ( MakeArgTuple ( call , nullptr , & args ) ) ; } CHECK ( args ) ; PyObject * result = PyEval_CallObject ( trampoline , args ) ; Py_DECREF ( args ) ; Status s = Status :: OK ( ) ; if ( result == nullptr ) { if ( PyErr_Occurred ( ) ) { if ( PyErr_ExceptionMatches ( PyExc_ValueError ) || PyErr_ExceptionMatches ( PyExc_TypeError ) ) { s = errors :: InvalidArgument ( PyExceptionFetch ( ) ) ; } else if ( PyErr_ExceptionMatches ( PyExc_StopIteration ) ) { * out_log_on_error = false ; s = errors :: OutOfRange ( PyExceptionFetch ( ) ) ; } else if ( PyErr_ExceptionMatches ( PyExc_MemoryError ) ) { s = errors :: ResourceExhausted ( PyExceptionFetch ( ) ) ; } else if ( PyErr_ExceptionMatches ( PyExc_NotImplementedError ) ) { s = errors :: Unimplemented ( PyExceptionFetch ( ) ) ; } else { s = errors :: Unknown ( PyExceptionFetch ( ) ) ; } } else { s = errors :: Internal ( " " , call -> token , " " ) ; } } TFE_Context * ctx = reinterpret_cast < TFE_Context * > ( PyCapsule_GetPointer ( PyObject_GetAttrString ( trampoline , " " ) , nullptr ) ) ; if ( new_executor != nullptr ) { s . Update ( new_executor -> WaitForAllPendingNodes ( ) ) ; tensorflow :: unwrap ( ctx ) -> SetExecutorForThread ( old_executor ) ; } TF_RETURN_IF_ERROR ( s ) ; if ( PyList_Check ( result ) ) { call -> out . clear ( ) ; for ( int i = 0 ; i < PyList_Size ( result ) ; ++ i ) { Tensor t ; if ( call -> eager ) { const PyObject * item = PyList_GetItem ( result , i ) ; if ( EagerTensor_CheckExact ( item ) ) { const Tensor * tensor = nullptr ; s = ExtractTensorFromEagerTensor ( item , ctx , call -> device , & tensor ) ; if ( s . ok ( ) ) t = * tensor ; } else { s = errors :: FailedPrecondition ( " " , Py_TYPE ( item ) -> tp_name ) ; } } else { s = NdarrayToTensor ( PyList_GetItem ( result , i ) , & t ) ; } if ( ! s . ok ( ) ) { break ; } call -> out . push_back ( t ) ; } } else if ( EagerTensor_CheckExact ( result ) || result == Py_None ) { DCHECK ( call -> eager ) ; if ( result != Py_None ) { const Tensor * t = nullptr ; s = ExtractTensorFromEagerTensor ( result , ctx , call -> device , & t ) ; if ( s . ok ( ) ) call -> out . push_back ( * t ) ; } } else if ( PyArray_Check ( result ) ) { DCHECK ( ! call -> eager ) ; if ( ! IsSingleNone ( result ) ) { Tensor t ; s = NdarrayToTensor ( result , & t ) ; if ( s . ok ( ) ) { call -> out . push_back ( t ) ; } } } else { s = errors :: Internal ( " " , Py_TYPE ( result ) -> tp_name ) ; } Py_DECREF ( result ) ; return s ; }
Calls the registered py function through the trampoline.
Calls the registered py function through the trampoline .
// Prepare the argument. // See FuncRegistry._ctx. // Invokes the trampoline. // TODO(ebrevdo): Check if exception is an OpError and use the // OpError.error_code property to map it back in the Status. /*name=*/ // Process the return values and convert them to TF Tensors. // `result` is a Python list; if this operation is an `EagerPyFunc`, then // every item in the list must be an `EagerTensor`; otherwise, every element // must be a NumPy array. // result is an `EagerTensor` or `None`. // `result` is a NumPy array.