Thanks to visit codestin.com
Credit goes to github.com

Skip to content

fix: map LRO errors to library exception types #86

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Oct 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 14 additions & 1 deletion google/api_core/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

try:
import grpc

except ImportError: # pragma: NO COVER
grpc = None

Expand All @@ -34,6 +35,14 @@
_HTTP_CODE_TO_EXCEPTION = {}
_GRPC_CODE_TO_EXCEPTION = {}

# Additional lookup table to map integer status codes to grpc status code
# grpc does not currently support initializing enums from ints
# i.e., grpc.StatusCode(5) raises an error
_INT_TO_GRPC_CODE = {}
if grpc is not None: # pragma: no branch
for x in grpc.StatusCode:
_INT_TO_GRPC_CODE[x.value[0]] = x


class GoogleAPIError(Exception):
"""Base class for all exceptions raised by Google API Clients."""
Expand Down Expand Up @@ -432,7 +441,7 @@ def from_grpc_status(status_code, message, **kwargs):
"""Create a :class:`GoogleAPICallError` from a :class:`grpc.StatusCode`.

Args:
status_code (grpc.StatusCode): The gRPC status code.
status_code (Union[grpc.StatusCode, int]): The gRPC status code.
message (str): The exception message.
kwargs: Additional arguments passed to the :class:`GoogleAPICallError`
constructor.
Expand All @@ -441,6 +450,10 @@ def from_grpc_status(status_code, message, **kwargs):
GoogleAPICallError: An instance of the appropriate subclass of
:class:`GoogleAPICallError`.
"""

if isinstance(status_code, int):
status_code = _INT_TO_GRPC_CODE.get(status_code, status_code)

error_class = exception_class_for_grpc_status(status_code)
error = error_class(message, **kwargs)

Expand Down
5 changes: 3 additions & 2 deletions google/api_core/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,9 @@ def _set_result_from_operation(self):
)
self.set_result(response)
elif self._operation.HasField("error"):
exception = exceptions.GoogleAPICallError(
self._operation.error.message,
exception = exceptions.from_grpc_status(
status_code=self._operation.error.code,
message=self._operation.error.message,
errors=(self._operation.error,),
response=self._operation,
)
Expand Down
11 changes: 11 additions & 0 deletions tests/unit/test_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,17 @@ def test_from_grpc_status():
assert exception.errors == []


def test_from_grpc_status_as_int():
message = "message"
exception = exceptions.from_grpc_status(11, message)
assert isinstance(exception, exceptions.BadRequest)
assert isinstance(exception, exceptions.OutOfRange)
assert exception.code == http_client.BAD_REQUEST
assert exception.grpc_status_code == grpc.StatusCode.OUT_OF_RANGE
assert exception.message == message
assert exception.errors == []


def test_from_grpc_status_with_errors_and_response():
message = "message"
response = mock.sentinel.response
Expand Down
17 changes: 17 additions & 0 deletions tests/unit/test_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,23 @@ def test_exception():
assert expected_exception.message in "{!r}".format(exception)


def test_exception_with_error_code():
expected_exception = status_pb2.Status(message="meep", code=5)
responses = [
make_operation_proto(),
# Second operation response includes the error.
make_operation_proto(done=True, error=expected_exception),
]
future, _, _ = make_operation_future(responses)

exception = future.exception()

assert expected_exception.message in "{!r}".format(exception)
# Status Code 5 maps to Not Found
# https://developers.google.com/maps-booking/reference/grpc-api/status_codes
assert isinstance(exception, exceptions.NotFound)


def test_unexpected_result():
responses = [
make_operation_proto(),
Expand Down