// This stores `_keras_mask` object and is set by Tensorflow layers.
PyObject* keras_mask;
+
+ // We store a status object here as an optimization to avoid allocating a new
+ // Status objects on different functions that operate on EagerTensor and need
+ // to use a TF_Status object. However note that accesses to `status` are not
+ // thread-safe.
+ TF_Status* status;
} EagerTensor;
// tp_init for EagerTensor.
self->handle_data = Py_None;
Py_INCREF(Py_None);
self->keras_mask = Py_None;
+ self->status = TF_NewStatus();
PyObject* value;
PyObject* context = nullptr;
PyObject* device = nullptr;
}
TF_DataType handle_dtype = TFE_TensorHandleDataType(handle.get());
if (desired_dtype >= 0 && desired_dtype != handle_dtype) {
- auto out_status = tensorflow::make_safe(TF_NewStatus());
handle = tensorflow::make_safe(
EagerCast(GetContext(context), handle.get(), handle_dtype,
- static_cast<TF_DataType>(desired_dtype), out_status.get()));
- if (TF_GetCode(out_status.get()) != TF_OK) {
- PyErr_SetString(
- PyExc_ValueError,
- tensorflow::strings::StrCat("Error while casting from DataType ",
- handle_dtype, " to ", desired_dtype, ". ",
- TF_Message(out_status.get()))
- .c_str());
+ static_cast<TF_DataType>(desired_dtype), self->status));
+ if (TF_GetCode(self->status) != TF_OK) {
+ PyErr_SetString(PyExc_ValueError,
+ tensorflow::strings::StrCat(
+ "Error while casting from DataType ", handle_dtype,
+ " to ", desired_dtype, ". ", TF_Message(self->status))
+ .c_str());
+ // Cleanup self->status before returning.
+ TF_SetStatus(self->status, TF_OK, "");
return -1;
}
handle_dtype = TFE_TensorHandleDataType(handle.get());
// tp_dealloc for EagerTensor.
void EagerTensor_dealloc(EagerTensor* self) {
+ TF_DeleteStatus(self->status);
Py_DECREF(self->handle_data);
Py_DECREF(self->keras_mask);
TFE_DeleteTensorHandle(self->handle);
// Getter for `_shape_tuple`.
static PyObject* EagerTensor_shape_tuple(EagerTensor* self) {
auto handle = self->handle;
- int n = TFE_TensorHandleNumDims(handle);
+ int n = TFE_TensorHandleNumDims(handle, self->status);
+ if (MaybeRaiseExceptionFromTFStatus(self->status, PyExc_ValueError)) {
+ // Cleanup self->status before returning.
+ TF_SetStatus(self->status, TF_OK, "");
+ return nullptr;
+ }
PyObject* shape = PyTuple_New(n);
if (PyErr_Occurred()) return nullptr;
for (int i = 0; i < n; ++i) {
- PyObject* dim = PyLong_FromLongLong(TFE_TensorHandleDim(handle, i));
- if (dim == nullptr || PyTuple_SetItem(shape, i, dim) != 0) {
+ PyObject* dim =
+ PyLong_FromLongLong(TFE_TensorHandleDim(handle, i, self->status));
+ if (MaybeRaiseExceptionFromTFStatus(self->status, PyExc_ValueError) ||
+ dim == nullptr || PyTuple_SetItem(shape, i, dim) != 0) {
+ // Cleanup self->status before returning.
+ TF_SetStatus(self->status, TF_OK, "");
Py_DECREF(shape);
if (dim != nullptr) Py_DECREF(dim);
PyErr_SetString(PyExc_RuntimeError, "Error while creating shape");
// Getter for `_rank`.
static PyObject* EagerTensor_rank(EagerTensor* self) {
+ int num_dims = TFE_TensorHandleNumDims(self->handle, self->status);
+ if (MaybeRaiseExceptionFromTFStatus(self->status, PyExc_ValueError)) {
+ // Cleanup self->status before returning.
+ TF_SetStatus(self->status, TF_OK, "");
+ return nullptr;
+ }
#if PY_MAJOR_VERSION < 3
- return PyInt_FromLong(TFE_TensorHandleNumDims(self->handle));
+ return PyInt_FromLong(num_dims);
#else
- return PyLong_FromLong(TFE_TensorHandleNumDims(self->handle));
+ return PyLong_FromLong(num_dims);
#endif
}
// Getter `device`.
static PyObject* EagerTensor_device(EagerTensor* self) {
+ const char* device = TFE_TensorHandleDeviceName(self->handle, self->status);
+ if (MaybeRaiseExceptionFromTFStatus(self->status, PyExc_ValueError)) {
+ // Cleanup self->status before returning.
+ TF_SetStatus(self->status, TF_OK, "");
+ return nullptr;
+ }
#if PY_MAJOR_VERSION >= 3
- return PyUnicode_FromString(TFE_TensorHandleDeviceName(self->handle));
+ return PyUnicode_FromString(device);
#else
- return PyBytes_FromString(TFE_TensorHandleDeviceName(self->handle));
+ return PyBytes_FromString(device);
#endif
}
Py_INCREF(Py_None);
t->keras_mask = Py_None;
t->handle = handle;
+ t->status = TF_NewStatus();
}
return reinterpret_cast<PyObject*>(t);
}
auto tensor = tensorflow::make_safe(TF_AllocateTensor(
TF_INT32, &num_tensors_int, /*num_dims=*/1, /*len=*/4 * num_tensors_int));
int32_t* data = reinterpret_cast<int32_t*>(TF_TensorData(tensor.get()));
+ auto status = tensorflow::make_safe(TF_NewStatus());
for (Py_ssize_t i = 0; i < num_tensors; ++i) {
PyObject* tensor_obj = PyList_GET_ITEM(tensor_list, i);
if (!EagerTensor_CheckExact(tensor_obj)) {
EagerTensor* t = reinterpret_cast<EagerTensor*>(tensor_obj);
TFE_TensorHandle* handle = t->handle;
- if (slice_dim >= TFE_TensorHandleNumDims(handle)) {
- PyErr_SetString(PyExc_IndexError,
- tensorflow::strings::StrCat(
- "Slice dimension (", slice_dim,
- ") must be smaller than rank of all "
- "tensors, but tensor at index ",
- i, " has rank ", TFE_TensorHandleNumDims(handle))
- .c_str());
+ int num_dims = TFE_TensorHandleNumDims(handle, status.get());
+ if (MaybeRaiseExceptionFromTFStatus(status.get(), PyExc_ValueError)) {
+ return nullptr;
+ }
+ if (slice_dim >= num_dims) {
+ PyErr_SetString(
+ PyExc_IndexError,
+ tensorflow::strings::StrCat("Slice dimension (", slice_dim,
+ ") must be smaller than rank of all "
+ "tensors, but tensor at index ",
+ i, " has rank ", num_dims)
+ .c_str());
+ return nullptr;
+ }
+ int64_t dim = TFE_TensorHandleDim(handle, slice_dim, status.get());
+ if (MaybeRaiseExceptionFromTFStatus(status.get(), PyExc_ValueError)) {
return nullptr;
}
- int64_t dim = TFE_TensorHandleDim(handle, slice_dim);
data[i] = dim;
}
- auto status = tensorflow::make_safe(TF_NewStatus());
TFE_TensorHandle* handle = TFE_NewTensorHandle(tensor.get(), status.get());
if (TF_GetCode(status.get()) != TF_OK) {
PyErr_SetString(