Calls the registered py function through the trampoline.
| 167 | |
| 168 | // Calls the registered py function through the trampoline. |
| 169 | Status DoCallPyFunc(PyCall* call, bool* out_log_on_error) { |
| 170 | *out_log_on_error = true; |
| 171 | PyObject* trampoline = GetPyTrampoline(); |
| 172 | if (trampoline == nullptr) { |
| 173 | return errors::InvalidArgument( |
| 174 | "Missing py trampoline. Most likely, it is a link error."); |
| 175 | } |
| 176 | |
| 177 | // Prepare the argument. |
| 178 | PyObject* args = nullptr; |
| 179 | TFE_Context* ctx = nullptr; |
| 180 | std::unique_ptr<EagerExecutor> new_executor = nullptr; |
| 181 | EagerExecutor* old_executor = nullptr; |
| 182 | if (call->eager) { |
| 183 | // See FuncRegistry._ctx. |
| 184 | ctx = reinterpret_cast<TFE_Context*>(PyCapsule_GetPointer( |
| 185 | PyObject_GetAttrString(trampoline, "_ctx"), nullptr)); |
| 186 | CHECK_NE(ctx, nullptr); |
| 187 | TF_RETURN_IF_ERROR(MakeArgTuple(call, ctx->context, &args)); |
| 188 | new_executor.reset(new EagerExecutor(call->eager_async)); |
| 189 | old_executor = ctx->context->Executor(); |
| 190 | ctx->context->SetExecutorForThread(new_executor.get()); |
| 191 | } else { |
| 192 | TF_RETURN_IF_ERROR(MakeArgTuple(call, nullptr, &args)); |
| 193 | } |
| 194 | CHECK(args); |
| 195 | |
| 196 | // Invokes the trampoline. |
| 197 | PyObject* result = PyEval_CallObject(trampoline, args); |
| 198 | Py_DECREF(args); |
| 199 | Status s = Status::OK(); |
| 200 | if (result == nullptr) { |
| 201 | if (PyErr_Occurred()) { |
| 202 | if (PyErr_ExceptionMatches(PyExc_ValueError) || |
| 203 | PyErr_ExceptionMatches(PyExc_TypeError)) { |
| 204 | s = errors::InvalidArgument(PyExceptionFetch()); |
| 205 | } else if (PyErr_ExceptionMatches(PyExc_StopIteration)) { |
| 206 | *out_log_on_error = false; |
| 207 | s = errors::OutOfRange(PyExceptionFetch()); |
| 208 | } else if (PyErr_ExceptionMatches(PyExc_MemoryError)) { |
| 209 | s = errors::ResourceExhausted(PyExceptionFetch()); |
| 210 | } else if (PyErr_ExceptionMatches(PyExc_NotImplementedError)) { |
| 211 | s = errors::Unimplemented(PyExceptionFetch()); |
| 212 | } else { |
| 213 | // TODO(ebrevdo): Check if exception is an OpError and use the |
| 214 | // OpError.error_code property to map it back in the Status. |
| 215 | s = errors::Unknown(PyExceptionFetch()); |
| 216 | } |
| 217 | } else { |
| 218 | s = errors::Internal("Failed to run py callback ", call->token, |
| 219 | ": see error log."); |
| 220 | } |
| 221 | } |
| 222 | |
| 223 | if (new_executor != nullptr) { |
| 224 | s.Update(new_executor->WaitForAllPendingNodes()); |
| 225 | ctx->context->SetExecutorForThread(old_executor); |
| 226 | } |
no test coverage detected