CC @atulep
The following commit causes a regression in the test suite:
commit ef6f0fcfdfe771172056e35e3c990998b3b00416
Author: Aza Tulepbergenov <aza.tulepber@gmail.com>
Date: 2021-10-19 20:17:49 +0200
feat: add 'GoogleAPICallError.error_details' property (#286)
Based on 'google.rpc.status.details'.
Prior to this commit, the package handled both missing and present grpc consistently. However, the following condition in exceptions.py:
try:
import grpc
from grpc_status import rpc_status
except ImportError: # pragma: NO COVER
grpc = None
rpc_status = None
means that if grpc_status module is not installed, the exception module behaves as if grpc wasn't present even though other modules (notably tests) behave as if it was present. As a result, people having one but not the other module installed get a bunch of test failures because grpc-based tests are run but e.g. the exception module's from_grpc_error() function fails since grpc is forced to None.
This is especially problematic since grpcio-status is a new optional dependency, and since it's not packaged on Gentoo, we'd effectively have to force people to uninstall grpcio.
Environment details
- OS type and version: Gentoo Linux
- Python version: python --version 3.8.12, 3.9.7
- pip version: pip --version n/a
- google-api-core version: pip show google-api-core 2.2.0, 2.2.1, git master (d2a729e)
Steps to reproduce
- git clone https://github.com/googleapis/python-api-core
- cd python-api-core
- python3.9 -m venv .venv
- . .venv/bin/activate
- pip install . grpcio pytest mock proto-plus pytest-asyncio
- pytest
Stack trace
Example test failure:
_______________________________________________________ test_wrap_unary_errors ________________________________________________________
self = <google.api_core.grpc_helpers_async._WrappedUnaryUnaryCall object at 0x7fe0e3de3790>
def __await__(self):
try:
> response = yield from self._call.__await__()
.venv/lib/python3.9/site-packages/google/api_core/grpc_helpers_async.py:84:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_mock_self = <AsyncMock id='140603872279952'>, args = (1, 2), kwargs = {'three': 'four'}, self = <AsyncMock id='140603872279952'>
_call = call(1, 2, three='four'), effect = RpcErrorImpl()
async def _execute_mock_call(_mock_self, *args, **kwargs):
self = _mock_self
# This is nearly just like super(), except for special handling
# of coroutines
_call = _Call((args, kwargs), two=True)
self.await_count += 1
self.await_args = _call
self.await_args_list.append(_call)
effect = self.side_effect
if effect is not None:
if _is_exception(effect):
> raise effect
E tests.asyncio.test_grpc_helpers_async.RpcErrorImpl
.venv/lib/python3.9/site-packages/mock/mock.py:2169: RpcErrorImpl
During handling of the above exception, another exception occurred:
@pytest.mark.asyncio
async def test_wrap_unary_errors():
grpc_error = RpcErrorImpl(grpc.StatusCode.INVALID_ARGUMENT)
callable_ = mock.AsyncMock(spec=["__call__"], side_effect=grpc_error)
wrapped_callable = grpc_helpers_async._wrap_unary_errors(callable_)
with pytest.raises(exceptions.InvalidArgument) as exc_info:
> await wrapped_callable(1, 2, three="four")
tests/asyncio/test_grpc_helpers_async.py:57:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
.venv/lib/python3.9/site-packages/google/api_core/grpc_helpers_async.py:87: in __await__
raise exceptions.from_grpc_error(rpc_error) from rpc_error
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
rpc_exc = RpcErrorImpl()
def from_grpc_error(rpc_exc):
"""Create a :class:`GoogleAPICallError` from a :class:`grpc.RpcError`.
Args:
rpc_exc (grpc.RpcError): The gRPC error.
Returns:
GoogleAPICallError: An instance of the appropriate subclass of
:class:`GoogleAPICallError`.
"""
# NOTE(lidiz) All gRPC error shares the parent class grpc.RpcError.
# However, check for grpc.RpcError breaks backward compatibility.
> if isinstance(rpc_exc, grpc.Call) or _is_informative_grpc_error(rpc_exc):
E AttributeError: 'NoneType' object has no attribute 'Call'
.venv/lib/python3.9/site-packages/google/api_core/exceptions.py:532: AttributeError
======================================================= short test summary info =======================================================
FAILED tests/asyncio/test_grpc_helpers_async.py::test_wrap_unary_errors - AttributeError: 'NoneType' object has no attribute 'Call'
CC @atulep
The following commit causes a regression in the test suite:
commit ef6f0fcfdfe771172056e35e3c990998b3b00416 Author: Aza Tulepbergenov <aza.tulepber@gmail.com> Date: 2021-10-19 20:17:49 +0200 feat: add 'GoogleAPICallError.error_details' property (#286) Based on 'google.rpc.status.details'.Prior to this commit, the package handled both missing and present grpc consistently. However, the following condition in exceptions.py:
try: import grpc from grpc_status import rpc_status except ImportError: # pragma: NO COVER grpc = None rpc_status = Nonemeans that if grpc_status module is not installed, the exception module behaves as if grpc wasn't present even though other modules (notably tests) behave as if it was present. As a result, people having one but not the other module installed get a bunch of test failures because grpc-based tests are run but e.g. the exception module's from_grpc_error() function fails since grpc is forced to None.
This is especially problematic since grpcio-status is a new optional dependency, and since it's not packaged on Gentoo, we'd effectively have to force people to uninstall grpcio.
Environment details
Steps to reproduce
Stack trace
Example test failure:
_______________________________________________________ test_wrap_unary_errors ________________________________________________________ self = <google.api_core.grpc_helpers_async._WrappedUnaryUnaryCall object at 0x7fe0e3de3790> def __await__(self): try: > response = yield from self._call.__await__() .venv/lib/python3.9/site-packages/google/api_core/grpc_helpers_async.py:84: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _mock_self = <AsyncMock id='140603872279952'>, args = (1, 2), kwargs = {'three': 'four'}, self = <AsyncMock id='140603872279952'> _call = call(1, 2, three='four'), effect = RpcErrorImpl() async def _execute_mock_call(_mock_self, *args, **kwargs): self = _mock_self # This is nearly just like super(), except for special handling # of coroutines _call = _Call((args, kwargs), two=True) self.await_count += 1 self.await_args = _call self.await_args_list.append(_call) effect = self.side_effect if effect is not None: if _is_exception(effect): > raise effect E tests.asyncio.test_grpc_helpers_async.RpcErrorImpl .venv/lib/python3.9/site-packages/mock/mock.py:2169: RpcErrorImpl During handling of the above exception, another exception occurred: @pytest.mark.asyncio async def test_wrap_unary_errors(): grpc_error = RpcErrorImpl(grpc.StatusCode.INVALID_ARGUMENT) callable_ = mock.AsyncMock(spec=["__call__"], side_effect=grpc_error) wrapped_callable = grpc_helpers_async._wrap_unary_errors(callable_) with pytest.raises(exceptions.InvalidArgument) as exc_info: > await wrapped_callable(1, 2, three="four") tests/asyncio/test_grpc_helpers_async.py:57: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ .venv/lib/python3.9/site-packages/google/api_core/grpc_helpers_async.py:87: in __await__ raise exceptions.from_grpc_error(rpc_error) from rpc_error _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ rpc_exc = RpcErrorImpl() def from_grpc_error(rpc_exc): """Create a :class:`GoogleAPICallError` from a :class:`grpc.RpcError`. Args: rpc_exc (grpc.RpcError): The gRPC error. Returns: GoogleAPICallError: An instance of the appropriate subclass of :class:`GoogleAPICallError`. """ # NOTE(lidiz) All gRPC error shares the parent class grpc.RpcError. # However, check for grpc.RpcError breaks backward compatibility. > if isinstance(rpc_exc, grpc.Call) or _is_informative_grpc_error(rpc_exc): E AttributeError: 'NoneType' object has no attribute 'Call' .venv/lib/python3.9/site-packages/google/api_core/exceptions.py:532: AttributeError ======================================================= short test summary info ======================================================= FAILED tests/asyncio/test_grpc_helpers_async.py::test_wrap_unary_errors - AttributeError: 'NoneType' object has no attribute 'Call'