diff options
author | Patrick Nguyen <drpng@google.com> | 2016-11-06 11:01:20 -0800 |
---|---|---|
committer | TensorFlower Gardener <gardener@tensorflow.org> | 2016-11-06 11:04:52 -0800 |
commit | 0409b0e9419d14314561273a1580731a8c9e7a85 (patch) | |
tree | 776e8cee7e6509e8eb6b10f844fcefe2d3e6bdd1 | |
parent | f45bb4ed8b467a7af06432cbb0535c8fe7b862f5 (diff) |
Seal errors interface.
Change: 138332031
-rw-r--r-- | tensorflow/python/BUILD | 7 | ||||
-rw-r--r-- | tensorflow/python/client/client_lib.py | 6 | ||||
-rw-r--r-- | tensorflow/python/framework/errors.py | 486 | ||||
-rw-r--r-- | tensorflow/python/framework/errors_impl.py | 471 | ||||
-rw-r--r-- | tensorflow/python/framework/errors_test.py | 8 | ||||
-rw-r--r-- | tensorflow/python/framework/load_library.py | 8 |
6 files changed, 528 insertions, 458 deletions
diff --git a/tensorflow/python/BUILD b/tensorflow/python/BUILD index 301761fbdc..34eb7ef56a 100644 --- a/tensorflow/python/BUILD +++ b/tensorflow/python/BUILD @@ -275,7 +275,6 @@ py_library( name = "framework", srcs = [ "framework/common_shapes.py", - "framework/errors.py", "framework/framework_lib.py", "framework/graph_util.py", "framework/graph_util_impl.py", @@ -290,6 +289,7 @@ py_library( srcs_version = "PY2AND3", deps = [ ":cpp_shape_inference_proto_py", + ":errors", ":framework_for_generated_wrappers", ":pywrap_tensorflow", ], @@ -297,7 +297,10 @@ py_library( py_library( name = "errors", - srcs = ["framework/errors.py"], + srcs = [ + "framework/errors.py", + "framework/errors_impl.py", + ], srcs_version = "PY2AND3", deps = [ ":util", diff --git a/tensorflow/python/client/client_lib.py b/tensorflow/python/client/client_lib.py index 21df1796d3..91f328205b 100644 --- a/tensorflow/python/client/client_lib.py +++ b/tensorflow/python/client/client_lib.py @@ -25,7 +25,7 @@ examples of how a graph is launched in a [`tf.Session`](#Session). @@get_default_session -## Error classes +## Error classes and convenience functions @@OpError @@CancelledError @@ -44,6 +44,10 @@ examples of how a graph is launched in a [`tf.Session`](#Session). @@InternalError @@UnavailableError @@DataLossError + +@@exception_type_from_error_code +@@error_code_from_exception_type +@@raise_exception_on_not_ok_status """ from __future__ import absolute_import diff --git a/tensorflow/python/framework/errors.py b/tensorflow/python/framework/errors.py index c99a710031..c8cf9ae39b 100644 --- a/tensorflow/python/framework/errors.py +++ b/tensorflow/python/framework/errors.py @@ -18,455 +18,19 @@ from __future__ import absolute_import from __future__ import division from __future__ import print_function -import contextlib -import traceback -import warnings - -from tensorflow.core.lib.core import error_codes_pb2 -from tensorflow.python import pywrap_tensorflow -from tensorflow.python.util import compat - - -class OpError(Exception): - """A generic error that is raised when TensorFlow execution fails. - - Whenever possible, the session will raise a more specific subclass - of `OpError` from the `tf.errors` module. - - @@op - @@node_def - """ - - def __init__(self, node_def, op, message, error_code): - """Creates a new `OpError` indicating that a particular op failed. - - Args: - node_def: The `node_def_pb2.NodeDef` proto representing the op that - failed, if known; otherwise None. - op: The `ops.Operation` that failed, if known; otherwise None. - message: The message string describing the failure. - error_code: The `error_codes_pb2.Code` describing the error. - """ - super(OpError, self).__init__() - self._message = message - self._node_def = node_def - self._op = op - self._error_code = error_code - - @property - def message(self): - """The error message that describes the error.""" - return self._message - - @property - def op(self): - """The operation that failed, if known. - - *N.B.* If the failed op was synthesized at runtime, e.g. a `Send` - or `Recv` op, there will be no corresponding - [`Operation`](../../api_docs/python/framework.md#Operation) - object. In that case, this will return `None`, and you should - instead use the [`OpError.node_def`](#OpError.node_def) to - discover information about the op. - - Returns: - The `Operation` that failed, or None. - """ - return self._op - - @property - def error_code(self): - """The integer error code that describes the error.""" - return self._error_code - - @property - def node_def(self): - """The `NodeDef` proto representing the op that failed.""" - return self._node_def - - def __str__(self): - if self._op is not None: - output = ["%s\n\nCaused by op %r, defined at:\n" % (self.message, - self._op.name,)] - curr_traceback_list = traceback.format_list(self._op.traceback) - output.extend(curr_traceback_list) - original_op = self._op._original_op - while original_op is not None: - output.append( - "\n...which was originally created as op %r, defined at:\n" - % (original_op.name,)) - prev_traceback_list = curr_traceback_list - curr_traceback_list = traceback.format_list(original_op.traceback) - - # Attempt to elide large common subsequences of the subsequent - # stack traces. - # - # TODO(mrry): Consider computing the actual longest common subsequence. - is_eliding = False - elide_count = 0 - last_elided_line = None - for line, line_in_prev in zip(curr_traceback_list, prev_traceback_list): - if line == line_in_prev: - if is_eliding: - elide_count += 1 - last_elided_line = line - else: - output.append(line) - is_eliding = True - elide_count = 0 - else: - if is_eliding: - if elide_count > 0: - output.extend( - ["[elided %d identical lines from previous traceback]\n" - % (elide_count - 1,), last_elided_line]) - is_eliding = False - output.extend(line) - - original_op = original_op._original_op - output.append("\n%s (see above for traceback): %s\n" % - (type(self).__name__, self.message)) - return ''.join(output) - else: - return self.message - - -OK = error_codes_pb2.OK -CANCELLED = error_codes_pb2.CANCELLED -UNKNOWN = error_codes_pb2.UNKNOWN -INVALID_ARGUMENT = error_codes_pb2.INVALID_ARGUMENT -DEADLINE_EXCEEDED = error_codes_pb2.DEADLINE_EXCEEDED -NOT_FOUND = error_codes_pb2.NOT_FOUND -ALREADY_EXISTS = error_codes_pb2.ALREADY_EXISTS -PERMISSION_DENIED = error_codes_pb2.PERMISSION_DENIED -UNAUTHENTICATED = error_codes_pb2.UNAUTHENTICATED -RESOURCE_EXHAUSTED = error_codes_pb2.RESOURCE_EXHAUSTED -FAILED_PRECONDITION = error_codes_pb2.FAILED_PRECONDITION -ABORTED = error_codes_pb2.ABORTED -OUT_OF_RANGE = error_codes_pb2.OUT_OF_RANGE -UNIMPLEMENTED = error_codes_pb2.UNIMPLEMENTED -INTERNAL = error_codes_pb2.INTERNAL -UNAVAILABLE = error_codes_pb2.UNAVAILABLE -DATA_LOSS = error_codes_pb2.DATA_LOSS - - -class CancelledError(OpError): - """Raised when an operation or step is cancelled. - - For example, a long-running operation (e.g. - [`queue.enqueue()`](../../api_docs/python/io_ops.md#QueueBase.enqueue) may be - cancelled by running another operation (e.g. - [`queue.close(cancel_pending_enqueues=True)`](../../api_docs/python/io_ops.md#QueueBase.close), - or by [closing the session](../../api_docs/python/client.md#Session.close). - A step that is running such a long-running operation will fail by raising - `CancelledError`. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates a `CancelledError`.""" - super(CancelledError, self).__init__(node_def, op, message, CANCELLED) - - -class UnknownError(OpError): - """Unknown error. - - An example of where this error may be returned is if a Status value - received from another address space belongs to an error-space that - is not known to this address space. Also errors raised by APIs that - do not return enough error information may be converted to this - error. - - @@__init__ - """ - - def __init__(self, node_def, op, message, error_code=UNKNOWN): - """Creates an `UnknownError`.""" - super(UnknownError, self).__init__(node_def, op, message, error_code) - - -class InvalidArgumentError(OpError): - """Raised when an operation receives an invalid argument. - - This may occur, for example, if an operation is receives an input - tensor that has an invalid value or shape. For example, the - [`tf.matmul()`](../../api_docs/python/math_ops.md#matmul) op will raise this - error if it receives an input that is not a matrix, and the - [`tf.reshape()`](../../api_docs/python/array_ops.md#reshape) op will raise - this error if the new shape does not match the number of elements in the input - tensor. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates an `InvalidArgumentError`.""" - super(InvalidArgumentError, self).__init__(node_def, op, message, - INVALID_ARGUMENT) - - -class DeadlineExceededError(OpError): - """Raised when a deadline expires before an operation could complete. - - This exception is not currently used. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates a `DeadlineExceededError`.""" - super(DeadlineExceededError, self).__init__(node_def, op, message, - DEADLINE_EXCEEDED) - - -class NotFoundError(OpError): - """Raised when a requested entity (e.g., a file or directory) was not found. - - For example, running the - [`tf.WholeFileReader.read()`](../../api_docs/python/io_ops.md#WholeFileReader) - operation could raise `NotFoundError` if it receives the name of a file that - does not exist. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates a `NotFoundError`.""" - super(NotFoundError, self).__init__(node_def, op, message, NOT_FOUND) - - -class AlreadyExistsError(OpError): - """Raised when an entity that we attempted to create already exists. - - For example, running an operation that saves a file - (e.g. [`tf.train.Saver.save()`](../../api_docs/python/train.md#Saver.save)) - could potentially raise this exception if an explicit filename for an - existing file was passed. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates an `AlreadyExistsError`.""" - super(AlreadyExistsError, self).__init__(node_def, op, message, - ALREADY_EXISTS) - - -class PermissionDeniedError(OpError): - """Raised when the caller does not have permission to run an operation. - - For example, running the - [`tf.WholeFileReader.read()`](../../api_docs/python/io_ops.md#WholeFileReader) - operation could raise `PermissionDeniedError` if it receives the name of a - file for which the user does not have the read file permission. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates a `PermissionDeniedError`.""" - super(PermissionDeniedError, self).__init__(node_def, op, message, - PERMISSION_DENIED) - - -class UnauthenticatedError(OpError): - """The request does not have valid authentication credentials. - - This exception is not currently used. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates an `UnauthenticatedError`.""" - super(UnauthenticatedError, self).__init__(node_def, op, message, - UNAUTHENTICATED) - - -class ResourceExhaustedError(OpError): - """Some resource has been exhausted. - - For example, this error might be raised if a per-user quota is - exhausted, or perhaps the entire file system is out of space. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates a `ResourceExhaustedError`.""" - super(ResourceExhaustedError, self).__init__(node_def, op, message, - RESOURCE_EXHAUSTED) - - -class FailedPreconditionError(OpError): - """Operation was rejected because the system is not in a state to execute it. - - This exception is most commonly raised when running an operation - that reads a [`tf.Variable`](../../api_docs/python/state_ops.md#Variable) - before it has been initialized. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates a `FailedPreconditionError`.""" - super(FailedPreconditionError, self).__init__(node_def, op, message, - FAILED_PRECONDITION) - - -class AbortedError(OpError): - """The operation was aborted, typically due to a concurrent action. - - For example, running a - [`queue.enqueue()`](../../api_docs/python/io_ops.md#QueueBase.enqueue) - operation may raise `AbortedError` if a - [`queue.close()`](../../api_docs/python/io_ops.md#QueueBase.close) operation - previously ran. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates an `AbortedError`.""" - super(AbortedError, self).__init__(node_def, op, message, ABORTED) - - -class OutOfRangeError(OpError): - """Raised when an operation iterates past the valid input range. - - This exception is raised in "end-of-file" conditions, such as when a - [`queue.dequeue()`](../../api_docs/python/io_ops.md#QueueBase.dequeue) - operation is blocked on an empty queue, and a - [`queue.close()`](../../api_docs/python/io_ops.md#QueueBase.close) - operation executes. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates an `OutOfRangeError`.""" - super(OutOfRangeError, self).__init__(node_def, op, message, - OUT_OF_RANGE) - - -class UnimplementedError(OpError): - """Raised when an operation has not been implemented. - - Some operations may raise this error when passed otherwise-valid - arguments that it does not currently support. For example, running - the [`tf.nn.max_pool()`](../../api_docs/python/nn.md#max_pool) operation - would raise this error if pooling was requested on the batch dimension, - because this is not yet supported. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates an `UnimplementedError`.""" - super(UnimplementedError, self).__init__(node_def, op, message, - UNIMPLEMENTED) - - -class InternalError(OpError): - """Raised when the system experiences an internal error. - - This exception is raised when some invariant expected by the runtime - has been broken. Catching this exception is not recommended. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates an `InternalError`.""" - super(InternalError, self).__init__(node_def, op, message, INTERNAL) - - -class UnavailableError(OpError): - """Raised when the runtime is currently unavailable. - - This exception is not currently used. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates an `UnavailableError`.""" - super(UnavailableError, self).__init__(node_def, op, message, - UNAVAILABLE) - - -class DataLossError(OpError): - """Raised when unrecoverable data loss or corruption is encountered. - - For example, this may be raised by running a - [`tf.WholeFileReader.read()`](../../api_docs/python/io_ops.md#WholeFileReader) - operation, if the file is truncated while it is being read. - - @@__init__ - """ - - def __init__(self, node_def, op, message): - """Creates a `DataLossError`.""" - super(DataLossError, self).__init__(node_def, op, message, DATA_LOSS) - - -_CODE_TO_EXCEPTION_CLASS = { - CANCELLED: CancelledError, - UNKNOWN: UnknownError, - INVALID_ARGUMENT: InvalidArgumentError, - DEADLINE_EXCEEDED: DeadlineExceededError, - NOT_FOUND: NotFoundError, - ALREADY_EXISTS: AlreadyExistsError, - PERMISSION_DENIED: PermissionDeniedError, - UNAUTHENTICATED: UnauthenticatedError, - RESOURCE_EXHAUSTED: ResourceExhaustedError, - FAILED_PRECONDITION: FailedPreconditionError, - ABORTED: AbortedError, - OUT_OF_RANGE: OutOfRangeError, - UNIMPLEMENTED: UnimplementedError, - INTERNAL: InternalError, - UNAVAILABLE: UnavailableError, - DATA_LOSS: DataLossError, -} - -_EXCEPTION_CLASS_TO_CODE = dict(( - (class_, code) for (code, class_) in _CODE_TO_EXCEPTION_CLASS.items())) - - -def exception_type_from_error_code(error_code): - return _CODE_TO_EXCEPTION_CLASS[error_code] - - -def error_code_from_exception_type(cls): - return _EXCEPTION_CLASS_TO_CODE[cls] - - -def _make_specific_exception(node_def, op, message, error_code): - try: - exc_type = exception_type_from_error_code(error_code) - return exc_type(node_def, op, message) - except KeyError: - warnings.warn("Unknown error code: %d" % error_code) - return UnknownError(node_def, op, message, error_code) - - -@contextlib.contextmanager -def raise_exception_on_not_ok_status(): - try: - status = pywrap_tensorflow.TF_NewStatus() - yield status - if pywrap_tensorflow.TF_GetCode(status) != 0: - raise _make_specific_exception( - None, None, - compat.as_text(pywrap_tensorflow.TF_Message(status)), - pywrap_tensorflow.TF_GetCode(status)) - finally: - pywrap_tensorflow.TF_DeleteStatus(status) - - -# These are documented in client/client_lib.py. -__all__ = [ +# pylint: disable=unused-import +from tensorflow.python.framework import errors_impl as _impl +# pylint: enable=unused-import +# go/tf-wildcard-import +# pylint: disable=wildcard-import +from tensorflow.python.framework.errors_impl import * +# pylint: enable=wildcard-import +from tensorflow.python.util.all_util import remove_undocumented + +# These are referenced in client/client_lib.py. +# Unfortunately, we can't import client_lib to examine +# the references, since it would create a dependency cycle. +_allowed_symbols = [ "AbortedError", "AlreadyExistsError", "CancelledError", @@ -476,6 +40,7 @@ __all__ = [ "InternalError", "InvalidArgumentError", "NotFoundError", + "OpError", "OutOfRangeError", "PermissionDeniedError", "ResourceExhaustedError", @@ -483,4 +48,27 @@ __all__ = [ "UnavailableError", "UnimplementedError", "UnknownError", + "error_code_from_exception_type", + "exception_type_from_error_code", + "raise_exception_on_not_ok_status", + # Scalars that have no docstrings: + "OK", + "CANCELLED", + "UNKNOWN", + "INVALID_ARGUMENT", + "DEADLINE_EXCEEDED", + "NOT_FOUND", + "ALREADY_EXISTS", + "PERMISSION_DENIED", + "UNAUTHENTICATED", + "RESOURCE_EXHAUSTED", + "FAILED_PRECONDITION", + "ABORTED", + "OUT_OF_RANGE", + "UNIMPLEMENTED", + "INTERNAL", + "UNAVAILABLE", + "DATA_LOSS", ] + +remove_undocumented(__name__, _allowed_symbols) diff --git a/tensorflow/python/framework/errors_impl.py b/tensorflow/python/framework/errors_impl.py new file mode 100644 index 0000000000..79e0b5f069 --- /dev/null +++ b/tensorflow/python/framework/errors_impl.py @@ -0,0 +1,471 @@ +# Copyright 2015 The TensorFlow Authors. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ============================================================================== +"""Exception types for TensorFlow errors.""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function + +import contextlib +import traceback +import warnings + +from tensorflow.core.lib.core import error_codes_pb2 +from tensorflow.python import pywrap_tensorflow +from tensorflow.python.util import compat + + +class OpError(Exception): + """A generic error that is raised when TensorFlow execution fails. + + Whenever possible, the session will raise a more specific subclass + of `OpError` from the `tf.errors` module. + + @@op + @@node_def + """ + + def __init__(self, node_def, op, message, error_code): + """Creates a new `OpError` indicating that a particular op failed. + + Args: + node_def: The `node_def_pb2.NodeDef` proto representing the op that + failed, if known; otherwise None. + op: The `ops.Operation` that failed, if known; otherwise None. + message: The message string describing the failure. + error_code: The `error_codes_pb2.Code` describing the error. + """ + super(OpError, self).__init__() + self._message = message + self._node_def = node_def + self._op = op + self._error_code = error_code + + @property + def message(self): + """The error message that describes the error.""" + return self._message + + @property + def op(self): + """The operation that failed, if known. + + *N.B.* If the failed op was synthesized at runtime, e.g. a `Send` + or `Recv` op, there will be no corresponding + [`Operation`](../../api_docs/python/framework.md#Operation) + object. In that case, this will return `None`, and you should + instead use the [`OpError.node_def`](#OpError.node_def) to + discover information about the op. + + Returns: + The `Operation` that failed, or None. + """ + return self._op + + @property + def error_code(self): + """The integer error code that describes the error.""" + return self._error_code + + @property + def node_def(self): + """The `NodeDef` proto representing the op that failed.""" + return self._node_def + + def __str__(self): + if self._op is not None: + output = ["%s\n\nCaused by op %r, defined at:\n" % (self.message, + self._op.name,)] + curr_traceback_list = traceback.format_list(self._op.traceback) + output.extend(curr_traceback_list) + # pylint: disable=protected-access + original_op = self._op._original_op + # pylint: enable=protected-access + while original_op is not None: + output.append( + "\n...which was originally created as op %r, defined at:\n" + % (original_op.name,)) + prev_traceback_list = curr_traceback_list + curr_traceback_list = traceback.format_list(original_op.traceback) + + # Attempt to elide large common subsequences of the subsequent + # stack traces. + # + # TODO(mrry): Consider computing the actual longest common subsequence. + is_eliding = False + elide_count = 0 + last_elided_line = None + for line, line_in_prev in zip(curr_traceback_list, prev_traceback_list): + if line == line_in_prev: + if is_eliding: + elide_count += 1 + last_elided_line = line + else: + output.append(line) + is_eliding = True + elide_count = 0 + else: + if is_eliding: + if elide_count > 0: + output.extend( + ["[elided %d identical lines from previous traceback]\n" + % (elide_count - 1,), last_elided_line]) + is_eliding = False + output.extend(line) + + # pylint: disable=protected-access + original_op = original_op._original_op + # pylint: enable=protected-access + output.append("\n%s (see above for traceback): %s\n" % + (type(self).__name__, self.message)) + return "".join(output) + else: + return self.message + + +OK = error_codes_pb2.OK +CANCELLED = error_codes_pb2.CANCELLED +UNKNOWN = error_codes_pb2.UNKNOWN +INVALID_ARGUMENT = error_codes_pb2.INVALID_ARGUMENT +DEADLINE_EXCEEDED = error_codes_pb2.DEADLINE_EXCEEDED +NOT_FOUND = error_codes_pb2.NOT_FOUND +ALREADY_EXISTS = error_codes_pb2.ALREADY_EXISTS +PERMISSION_DENIED = error_codes_pb2.PERMISSION_DENIED +UNAUTHENTICATED = error_codes_pb2.UNAUTHENTICATED +RESOURCE_EXHAUSTED = error_codes_pb2.RESOURCE_EXHAUSTED +FAILED_PRECONDITION = error_codes_pb2.FAILED_PRECONDITION +ABORTED = error_codes_pb2.ABORTED +OUT_OF_RANGE = error_codes_pb2.OUT_OF_RANGE +UNIMPLEMENTED = error_codes_pb2.UNIMPLEMENTED +INTERNAL = error_codes_pb2.INTERNAL +UNAVAILABLE = error_codes_pb2.UNAVAILABLE +DATA_LOSS = error_codes_pb2.DATA_LOSS + + +# pylint: disable=line-too-long +class CancelledError(OpError): + """Raised when an operation or step is cancelled. + + For example, a long-running operation (e.g. + [`queue.enqueue()`](../../api_docs/python/io_ops.md#QueueBase.enqueue) may be + cancelled by running another operation (e.g. + [`queue.close(cancel_pending_enqueues=True)`](../../api_docs/python/io_ops.md#QueueBase.close), + or by [closing the session](../../api_docs/python/client.md#Session.close). + A step that is running such a long-running operation will fail by raising + `CancelledError`. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates a `CancelledError`.""" + super(CancelledError, self).__init__(node_def, op, message, CANCELLED) +# pylint: enable=line-too-long + + +class UnknownError(OpError): + """Unknown error. + + An example of where this error may be returned is if a Status value + received from another address space belongs to an error-space that + is not known to this address space. Also errors raised by APIs that + do not return enough error information may be converted to this + error. + + @@__init__ + """ + + def __init__(self, node_def, op, message, error_code=UNKNOWN): + """Creates an `UnknownError`.""" + super(UnknownError, self).__init__(node_def, op, message, error_code) + + +class InvalidArgumentError(OpError): + """Raised when an operation receives an invalid argument. + + This may occur, for example, if an operation is receives an input + tensor that has an invalid value or shape. For example, the + [`tf.matmul()`](../../api_docs/python/math_ops.md#matmul) op will raise this + error if it receives an input that is not a matrix, and the + [`tf.reshape()`](../../api_docs/python/array_ops.md#reshape) op will raise + this error if the new shape does not match the number of elements in the input + tensor. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates an `InvalidArgumentError`.""" + super(InvalidArgumentError, self).__init__(node_def, op, message, + INVALID_ARGUMENT) + + +class DeadlineExceededError(OpError): + """Raised when a deadline expires before an operation could complete. + + This exception is not currently used. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates a `DeadlineExceededError`.""" + super(DeadlineExceededError, self).__init__(node_def, op, message, + DEADLINE_EXCEEDED) + + +class NotFoundError(OpError): + """Raised when a requested entity (e.g., a file or directory) was not found. + + For example, running the + [`tf.WholeFileReader.read()`](../../api_docs/python/io_ops.md#WholeFileReader) + operation could raise `NotFoundError` if it receives the name of a file that + does not exist. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates a `NotFoundError`.""" + super(NotFoundError, self).__init__(node_def, op, message, NOT_FOUND) + + +class AlreadyExistsError(OpError): + """Raised when an entity that we attempted to create already exists. + + For example, running an operation that saves a file + (e.g. [`tf.train.Saver.save()`](../../api_docs/python/train.md#Saver.save)) + could potentially raise this exception if an explicit filename for an + existing file was passed. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates an `AlreadyExistsError`.""" + super(AlreadyExistsError, self).__init__(node_def, op, message, + ALREADY_EXISTS) + + +class PermissionDeniedError(OpError): + """Raised when the caller does not have permission to run an operation. + + For example, running the + [`tf.WholeFileReader.read()`](../../api_docs/python/io_ops.md#WholeFileReader) + operation could raise `PermissionDeniedError` if it receives the name of a + file for which the user does not have the read file permission. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates a `PermissionDeniedError`.""" + super(PermissionDeniedError, self).__init__(node_def, op, message, + PERMISSION_DENIED) + + +class UnauthenticatedError(OpError): + """The request does not have valid authentication credentials. + + This exception is not currently used. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates an `UnauthenticatedError`.""" + super(UnauthenticatedError, self).__init__(node_def, op, message, + UNAUTHENTICATED) + + +class ResourceExhaustedError(OpError): + """Some resource has been exhausted. + + For example, this error might be raised if a per-user quota is + exhausted, or perhaps the entire file system is out of space. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates a `ResourceExhaustedError`.""" + super(ResourceExhaustedError, self).__init__(node_def, op, message, + RESOURCE_EXHAUSTED) + + +class FailedPreconditionError(OpError): + """Operation was rejected because the system is not in a state to execute it. + + This exception is most commonly raised when running an operation + that reads a [`tf.Variable`](../../api_docs/python/state_ops.md#Variable) + before it has been initialized. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates a `FailedPreconditionError`.""" + super(FailedPreconditionError, self).__init__(node_def, op, message, + FAILED_PRECONDITION) + + +class AbortedError(OpError): + """The operation was aborted, typically due to a concurrent action. + + For example, running a + [`queue.enqueue()`](../../api_docs/python/io_ops.md#QueueBase.enqueue) + operation may raise `AbortedError` if a + [`queue.close()`](../../api_docs/python/io_ops.md#QueueBase.close) operation + previously ran. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates an `AbortedError`.""" + super(AbortedError, self).__init__(node_def, op, message, ABORTED) + + +class OutOfRangeError(OpError): + """Raised when an operation iterates past the valid input range. + + This exception is raised in "end-of-file" conditions, such as when a + [`queue.dequeue()`](../../api_docs/python/io_ops.md#QueueBase.dequeue) + operation is blocked on an empty queue, and a + [`queue.close()`](../../api_docs/python/io_ops.md#QueueBase.close) + operation executes. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates an `OutOfRangeError`.""" + super(OutOfRangeError, self).__init__(node_def, op, message, + OUT_OF_RANGE) + + +class UnimplementedError(OpError): + """Raised when an operation has not been implemented. + + Some operations may raise this error when passed otherwise-valid + arguments that it does not currently support. For example, running + the [`tf.nn.max_pool()`](../../api_docs/python/nn.md#max_pool) operation + would raise this error if pooling was requested on the batch dimension, + because this is not yet supported. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates an `UnimplementedError`.""" + super(UnimplementedError, self).__init__(node_def, op, message, + UNIMPLEMENTED) + + +class InternalError(OpError): + """Raised when the system experiences an internal error. + + This exception is raised when some invariant expected by the runtime + has been broken. Catching this exception is not recommended. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates an `InternalError`.""" + super(InternalError, self).__init__(node_def, op, message, INTERNAL) + + +class UnavailableError(OpError): + """Raised when the runtime is currently unavailable. + + This exception is not currently used. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates an `UnavailableError`.""" + super(UnavailableError, self).__init__(node_def, op, message, + UNAVAILABLE) + + +class DataLossError(OpError): + """Raised when unrecoverable data loss or corruption is encountered. + + For example, this may be raised by running a + [`tf.WholeFileReader.read()`](../../api_docs/python/io_ops.md#WholeFileReader) + operation, if the file is truncated while it is being read. + + @@__init__ + """ + + def __init__(self, node_def, op, message): + """Creates a `DataLossError`.""" + super(DataLossError, self).__init__(node_def, op, message, DATA_LOSS) + + +_CODE_TO_EXCEPTION_CLASS = { + CANCELLED: CancelledError, + UNKNOWN: UnknownError, + INVALID_ARGUMENT: InvalidArgumentError, + DEADLINE_EXCEEDED: DeadlineExceededError, + NOT_FOUND: NotFoundError, + ALREADY_EXISTS: AlreadyExistsError, + PERMISSION_DENIED: PermissionDeniedError, + UNAUTHENTICATED: UnauthenticatedError, + RESOURCE_EXHAUSTED: ResourceExhaustedError, + FAILED_PRECONDITION: FailedPreconditionError, + ABORTED: AbortedError, + OUT_OF_RANGE: OutOfRangeError, + UNIMPLEMENTED: UnimplementedError, + INTERNAL: InternalError, + UNAVAILABLE: UnavailableError, + DATA_LOSS: DataLossError, +} + +_EXCEPTION_CLASS_TO_CODE = dict(( + (class_, code) for (code, class_) in _CODE_TO_EXCEPTION_CLASS.items())) + + +def exception_type_from_error_code(error_code): + return _CODE_TO_EXCEPTION_CLASS[error_code] + + +def error_code_from_exception_type(cls): + return _EXCEPTION_CLASS_TO_CODE[cls] + + +def _make_specific_exception(node_def, op, message, error_code): + try: + exc_type = exception_type_from_error_code(error_code) + return exc_type(node_def, op, message) + except KeyError: + warnings.warn("Unknown error code: %d" % error_code) + return UnknownError(node_def, op, message, error_code) + + +@contextlib.contextmanager +def raise_exception_on_not_ok_status(): + try: + status = pywrap_tensorflow.TF_NewStatus() + yield status + if pywrap_tensorflow.TF_GetCode(status) != 0: + raise _make_specific_exception( + None, None, + compat.as_text(pywrap_tensorflow.TF_Message(status)), + pywrap_tensorflow.TF_GetCode(status)) + finally: + pywrap_tensorflow.TF_DeleteStatus(status) diff --git a/tensorflow/python/framework/errors_test.py b/tensorflow/python/framework/errors_test.py index fa25427269..356bf9cbee 100644 --- a/tensorflow/python/framework/errors_test.py +++ b/tensorflow/python/framework/errors_test.py @@ -47,7 +47,8 @@ class ErrorsTest(tf.test.TestCase): ]: # pylint: disable=protected-access self.assertTrue(isinstance( - tf.errors._make_specific_exception(None, None, None, error_code), + tf.errors._impl._make_specific_exception( + None, None, None, error_code), exc_type)) # pylint: enable=protected-access @@ -60,7 +61,8 @@ class ErrorsTest(tf.test.TestCase): # pylint: enable=line-too-long with warnings.catch_warnings(record=True) as w: # pylint: disable=protected-access - exc = tf.errors._make_specific_exception(None, None, None, error_code) + exc = tf.errors._impl._make_specific_exception( + None, None, None, error_code) # pylint: enable=protected-access self.assertEqual(0, len(w)) # No warning is raised. self.assertTrue(isinstance(exc, tf.OpError)) @@ -69,7 +71,7 @@ class ErrorsTest(tf.test.TestCase): def testUnknownErrorCodeCausesWarning(self): with warnings.catch_warnings(record=True) as w: # pylint: disable=protected-access - exc = tf.errors._make_specific_exception(None, None, None, 37) + exc = tf.errors._impl._make_specific_exception(None, None, None, 37) # pylint: enable=protected-access self.assertEqual(1, len(w)) self.assertTrue("Unknown error code: 37" in str(w[0].message)) diff --git a/tensorflow/python/framework/load_library.py b/tensorflow/python/framework/load_library.py index e6fe05062a..5520681940 100644 --- a/tensorflow/python/framework/load_library.py +++ b/tensorflow/python/framework/load_library.py @@ -26,7 +26,7 @@ import threading from tensorflow.core.framework import op_def_pb2 from tensorflow.core.lib.core import error_codes_pb2 from tensorflow.python import pywrap_tensorflow as py_tf -from tensorflow.python.framework import errors +from tensorflow.python.framework import errors_impl from tensorflow.python.util import compat @@ -60,7 +60,8 @@ def load_op_library(library_filename): if error_code != 0: error_msg = compat.as_text(py_tf.TF_Message(status)) # pylint: disable=protected-access - raise errors._make_specific_exception(None, None, error_msg, error_code) + raise errors_impl._make_specific_exception( + None, None, error_msg, error_code) # pylint: enable=protected-access finally: py_tf.TF_DeleteStatus(status) @@ -109,7 +110,8 @@ def load_file_system_library(library_filename): if error_code != 0: error_msg = compat.as_text(py_tf.TF_Message(status)) # pylint: disable=protected-access - raise errors._make_specific_exception(None, None, error_msg, error_code) + raise errors_impl._make_specific_exception( + None, None, error_msg, error_code) # pylint: enable=protected-access finally: py_tf.TF_DeleteStatus(status) |