ortools.math_opt.python.errors

Translate C++'s absl::Status errors to Python standard errors.

Here we try to use the standard Python errors we would use if the C++ code was instead implemented in Python. This will give Python users a more familiar API.

  1# Copyright 2010-2024 Google LLC
  2# Licensed under the Apache License, Version 2.0 (the "License");
  3# you may not use this file except in compliance with the License.
  4# You may obtain a copy of the License at
  5#
  6#     http://www.apache.org/licenses/LICENSE-2.0
  7#
  8# Unless required by applicable law or agreed to in writing, software
  9# distributed under the License is distributed on an "AS IS" BASIS,
 10# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 11# See the License for the specific language governing permissions and
 12# limitations under the License.
 13
 14"""Translate C++'s absl::Status errors to Python standard errors.
 15
 16Here we try to use the standard Python errors we would use if the C++ code was
 17instead implemented in Python. This will give Python users a more familiar API.
 18"""
 19
 20import enum
 21from typing import Optional, Type
 22from ortools.math_opt import rpc_pb2
 23
 24
 25class _StatusCode(enum.Enum):
 26    """The C++ absl::Status::code() values."""
 27
 28    OK = 0
 29    CANCELLED = 1
 30    UNKNOWN = 2
 31    INVALID_ARGUMENT = 3
 32    DEADLINE_EXCEEDED = 4
 33    NOT_FOUND = 5
 34    ALREADY_EXISTS = 6
 35    PERMISSION_DENIED = 7
 36    UNAUTHENTICATED = 16
 37    RESOURCE_EXHAUSTED = 8
 38    FAILED_PRECONDITION = 9
 39    ABORTED = 10
 40    OUT_OF_RANGE = 11
 41    UNIMPLEMENTED = 12
 42    INTERNAL = 13
 43    UNAVAILABLE = 14
 44    DATA_LOSS = 15
 45
 46
 47class InternalMathOptError(RuntimeError):
 48    """Some MathOpt internal error.
 49
 50    This error is usually raised because of a bug in MathOpt or one of the solver
 51    library it wraps.
 52    """
 53
 54
 55def status_proto_to_exception(
 56    status_proto: rpc_pb2.StatusProto,
 57) -> Optional[Exception]:
 58    """Returns the Python exception that best match the input absl::Status.
 59
 60    There are some Status that we expect the MathOpt code to return, for those the
 61    matching exceptions are:
 62    - InvalidArgument: ValueError
 63    - FailedPrecondition: AssertionError
 64    - Unimplemented: NotImplementedError
 65    - Internal: InternalMathOptError
 66
 67    Other Status's are not used by MathOpt, if they are seen a
 68    InternalMathOptError is raised (as if the Status was Internal) and the error
 69    message contains the unexpected code.
 70
 71    Args:
 72      status_proto: The input proto to convert to an exception.
 73
 74    Returns:
 75      The corresponding exception. None if the input status is OK.
 76    """
 77    try:
 78        code = _StatusCode(status_proto.code)
 79    except ValueError:
 80        return InternalMathOptError(
 81            f"unknown C++ error (code = {status_proto.code}):"
 82            f" {status_proto.message}"
 83        )
 84
 85    if code == _StatusCode.OK:
 86        return None
 87
 88    # For expected errors we compute the corresponding class.
 89    error_type: Optional[Type[Exception]] = None
 90    if code == _StatusCode.INVALID_ARGUMENT:
 91        error_type = ValueError
 92    if code == _StatusCode.FAILED_PRECONDITION:
 93        error_type = AssertionError
 94    if code == _StatusCode.UNIMPLEMENTED:
 95        error_type = NotImplementedError
 96    if code == _StatusCode.INTERNAL:
 97        error_type = InternalMathOptError
 98
 99    if error_type is not None:
100        return error_type(f"{status_proto.message} (was C++ {code.name})")
101
102    return InternalMathOptError(
103        f"unexpected C++ error {code.name}: {status_proto.message}"
104    )
class InternalMathOptError(builtins.RuntimeError):
48class InternalMathOptError(RuntimeError):
49    """Some MathOpt internal error.
50
51    This error is usually raised because of a bug in MathOpt or one of the solver
52    library it wraps.
53    """

Some MathOpt internal error.

This error is usually raised because of a bug in MathOpt or one of the solver library it wraps.

Inherited Members
builtins.RuntimeError
RuntimeError
builtins.BaseException
with_traceback
add_note
args
def status_proto_to_exception( status_proto: ortools.math_opt.rpc_pb2.StatusProto) -> Optional[Exception]:
 56def status_proto_to_exception(
 57    status_proto: rpc_pb2.StatusProto,
 58) -> Optional[Exception]:
 59    """Returns the Python exception that best match the input absl::Status.
 60
 61    There are some Status that we expect the MathOpt code to return, for those the
 62    matching exceptions are:
 63    - InvalidArgument: ValueError
 64    - FailedPrecondition: AssertionError
 65    - Unimplemented: NotImplementedError
 66    - Internal: InternalMathOptError
 67
 68    Other Status's are not used by MathOpt, if they are seen a
 69    InternalMathOptError is raised (as if the Status was Internal) and the error
 70    message contains the unexpected code.
 71
 72    Args:
 73      status_proto: The input proto to convert to an exception.
 74
 75    Returns:
 76      The corresponding exception. None if the input status is OK.
 77    """
 78    try:
 79        code = _StatusCode(status_proto.code)
 80    except ValueError:
 81        return InternalMathOptError(
 82            f"unknown C++ error (code = {status_proto.code}):"
 83            f" {status_proto.message}"
 84        )
 85
 86    if code == _StatusCode.OK:
 87        return None
 88
 89    # For expected errors we compute the corresponding class.
 90    error_type: Optional[Type[Exception]] = None
 91    if code == _StatusCode.INVALID_ARGUMENT:
 92        error_type = ValueError
 93    if code == _StatusCode.FAILED_PRECONDITION:
 94        error_type = AssertionError
 95    if code == _StatusCode.UNIMPLEMENTED:
 96        error_type = NotImplementedError
 97    if code == _StatusCode.INTERNAL:
 98        error_type = InternalMathOptError
 99
100    if error_type is not None:
101        return error_type(f"{status_proto.message} (was C++ {code.name})")
102
103    return InternalMathOptError(
104        f"unexpected C++ error {code.name}: {status_proto.message}"
105    )

Returns the Python exception that best match the input absl::Status.

There are some Status that we expect the MathOpt code to return, for those the matching exceptions are:

  • InvalidArgument: ValueError
  • FailedPrecondition: AssertionError
  • Unimplemented: NotImplementedError
  • Internal: InternalMathOptError

Other Status's are not used by MathOpt, if they are seen a InternalMathOptError is raised (as if the Status was Internal) and the error message contains the unexpected code.

Arguments:
  • status_proto: The input proto to convert to an exception.
Returns:

The corresponding exception. None if the input status is OK.