diff --git a/src/grpcutil/__init__.py b/src/grpcutil/__init__.py index 143900a..71f7457 100644 --- a/src/grpcutil/__init__.py +++ b/src/grpcutil/__init__.py @@ -2,6 +2,17 @@ import grpc +# Unified exception type for catching errors from both the sync and async +# clients. grpc.aio.AioRpcError (raised by the async client) already subclasses +# grpc.RpcError (raised by the sync client), so a single ``except AuthzedError`` +# catches errors from either: +# +# try: +# client.CheckPermission(...) +# except AuthzedError as err: +# ... +AuthzedError = grpc.RpcError + def bearer_token_credentials(token: str, certChain: Optional[bytes] = None): """ diff --git a/tests/misc_test.py b/tests/misc_test.py index dcd96d6..e7249c7 100644 --- a/tests/misc_test.py +++ b/tests/misc_test.py @@ -1,7 +1,20 @@ +import grpc +import grpc.aio import pytest from protovalidate import ValidationError, validate from authzed.api.v1 import ObjectReference, Relationship +from grpcutil import AuthzedError + + +def test_authzed_error_catches_sync_and_async_grpc_errors(): + # The sync client raises grpc.RpcError; the async client raises + # grpc.aio.AioRpcError. AuthzedError must catch both. + with pytest.raises(AuthzedError): + raise grpc.RpcError("sync error") + + assert issubclass(grpc.RpcError, AuthzedError) + assert issubclass(grpc.aio.AioRpcError, AuthzedError) def test_type_error_does_not_segfault():