From b51b7f587042fe9340371c1b5c8e9adf8001c43a Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Mon, 28 Dec 2020 12:20:12 -0800 Subject: [PATCH 1/6] docs(python): document adding Python 3.9 support, dropping 3.5 support (#120) Closes #787 Source-Author: Tres Seaver Source-Date: Thu Dec 17 16:08:02 2020 -0500 Source-Repo: googleapis/synthtool Source-Sha: b670a77a454f415d247907908e8ee7943e06d718 Source-Link: https://github.com/googleapis/synthtool/commit/b670a77a454f415d247907908e8ee7943e06d718 --- CONTRIBUTING.rst | 11 +++++------ synth.metadata | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index 3f971e6a..643fbdbb 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -21,8 +21,8 @@ In order to add a feature: - The feature must be documented in both the API and narrative documentation. -- The feature must work fully on the following CPython versions: 2.7, - 3.5, 3.6, 3.7 and 3.8 on both UNIX and Windows. +- The feature must work fully on the following CPython versions: + 3.6, 3.7, 3.8 and 3.9 on both UNIX and Windows. - The feature must not add unnecessary dependencies (where "unnecessary" is of course subjective, but new dependencies should @@ -202,25 +202,24 @@ Supported Python Versions We support: -- `Python 3.5`_ - `Python 3.6`_ - `Python 3.7`_ - `Python 3.8`_ +- `Python 3.9`_ -.. _Python 3.5: https://docs.python.org/3.5/ .. _Python 3.6: https://docs.python.org/3.6/ .. _Python 3.7: https://docs.python.org/3.7/ .. _Python 3.8: https://docs.python.org/3.8/ +.. _Python 3.9: https://docs.python.org/3.9/ Supported versions can be found in our ``noxfile.py`` `config`_. .. _config: https://github.com/googleapis/python-api-core/blob/master/noxfile.py -Python 2.7 support is deprecated. All code changes should maintain Python 2.7 compatibility until January 1, 2020. We also explicitly decided to support Python 3 beginning with version -3.5. Reasons for this include: +3.6. Reasons for this include: - Encouraging use of newest versions of Python 3 - Taking the lead of `prominent`_ open-source `projects`_ diff --git a/synth.metadata b/synth.metadata index 5885a7d8..caf45afe 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,14 +4,14 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/python-api-core.git", - "sha": "7a38243c351b228d103eee81fc5ae521ad1c930e" + "sha": "4e12b76573e2a1726b0a59a5accc99532e010732" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "aa255b15d52b6d8950cca48cfdf58f7d27a60c8a" + "sha": "b670a77a454f415d247907908e8ee7943e06d718" } } ], From c2f094b1204c81f2db59ad6d11bb6c5c516fde58 Mon Sep 17 00:00:00 2001 From: Yoshi Automation Bot Date: Wed, 13 Jan 2021 13:28:09 -0800 Subject: [PATCH 2/6] chore: use 'http' in URL for Apache license (#125) * chore(python): fix column sizing issue in docs Source-Author: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Source-Date: Thu Jan 7 11:58:32 2021 -0700 Source-Repo: googleapis/synthtool Source-Sha: f15b57ccfd71106c2299e9b89835fe6e55015662 Source-Link: https://github.com/googleapis/synthtool/commit/f15b57ccfd71106c2299e9b89835fe6e55015662 * chore(python): use 'http' in LICENSE Co-authored-by: Tim Swast Source-Author: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Source-Date: Thu Jan 7 13:05:12 2021 -0700 Source-Repo: googleapis/synthtool Source-Sha: 41a4e56982620d3edcf110d76f4fcdfdec471ac8 Source-Link: https://github.com/googleapis/synthtool/commit/41a4e56982620d3edcf110d76f4fcdfdec471ac8 --- LICENSE | 7 ++++--- docs/_static/custom.css | 7 ++++++- synth.metadata | 4 ++-- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/LICENSE b/LICENSE index a8ee855d..d6456956 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,7 @@ - Apache License + + Apache License Version 2.0, January 2004 - https://www.apache.org/licenses/ + http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION @@ -192,7 +193,7 @@ you may not use this file except in compliance with the License. You may obtain a copy of the License at - https://www.apache.org/licenses/LICENSE-2.0 + 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, diff --git a/docs/_static/custom.css b/docs/_static/custom.css index 0abaf229..bcd37bbd 100644 --- a/docs/_static/custom.css +++ b/docs/_static/custom.css @@ -1,4 +1,9 @@ div#python2-eol { border-color: red; border-width: medium; -} \ No newline at end of file +} + +/* Ensure minimum width for 'Parameters' / 'Returns' column */ +dl.field-list > dt { + min-width: 100px +} diff --git a/synth.metadata b/synth.metadata index caf45afe..1e35d075 100644 --- a/synth.metadata +++ b/synth.metadata @@ -4,14 +4,14 @@ "git": { "name": ".", "remote": "https://github.com/googleapis/python-api-core.git", - "sha": "4e12b76573e2a1726b0a59a5accc99532e010732" + "sha": "b51b7f587042fe9340371c1b5c8e9adf8001c43a" } }, { "git": { "name": "synthtool", "remote": "https://github.com/googleapis/synthtool.git", - "sha": "b670a77a454f415d247907908e8ee7943e06d718" + "sha": "41a4e56982620d3edcf110d76f4fcdfdec471ac8" } } ], From c5fee8947b466484b4dc40a482db4b89415c3e51 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Wed, 13 Jan 2021 14:46:03 -0700 Subject: [PATCH 3/6] chore: add constraints file (#122) Add constraints file to test lower bounds. --- noxfile.py | 16 ++++++++++++---- setup.py | 2 +- testing/constraints-2.7.txt | 0 testing/constraints-3.10.txt | 0 testing/constraints-3.11.txt | 0 testing/constraints-3.6.txt | 16 ++++++++++++++++ testing/constraints-3.7.txt | 0 testing/constraints-3.8.txt | 0 testing/constraints-3.9.txt | 0 9 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 testing/constraints-2.7.txt create mode 100644 testing/constraints-3.10.txt create mode 100644 testing/constraints-3.11.txt create mode 100644 testing/constraints-3.6.txt create mode 100644 testing/constraints-3.7.txt create mode 100644 testing/constraints-3.8.txt create mode 100644 testing/constraints-3.9.txt diff --git a/noxfile.py b/noxfile.py index 86758e1f..650cef28 100644 --- a/noxfile.py +++ b/noxfile.py @@ -14,13 +14,15 @@ from __future__ import absolute_import import os +import pathlib import shutil # https://github.com/google/importlab/issues/25 import nox # pytype: disable=import-error -_MINIMAL_ASYNCIO_SUPPORT_PYTHON_VERSION = [3, 6] +CURRENT_DIRECTORY = pathlib.Path(__file__).parent.absolute() +_MINIMAL_ASYNCIO_SUPPORT_PYTHON_VERSION = [3, 6] def _greater_or_equal_than_36(version_string): tokens = version_string.split(".") @@ -40,9 +42,13 @@ def default(session): Python corresponding to the ``nox`` binary the ``PATH`` can run the tests. """ + constraints_path = str( + CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" + ) + # Install all test dependencies, then install this package in-place. session.install("mock", "pytest", "pytest-cov", "grpcio >= 1.0.2") - session.install("-e", ".") + session.install("-e", ".", "-c", constraints_path) pytest_args = [ "python", @@ -80,9 +86,11 @@ def unit(session): @nox.session(python=["2.7", "3.6", "3.7", "3.8", "3.9"]) def unit_grpc_gcp(session): """Run the unit test suite with grpcio-gcp installed.""" - + constraints_path = str( + CURRENT_DIRECTORY / "testing" / f"constraints-{session.python}.txt" + ) # Install grpcio-gcp - session.install("grpcio-gcp") + session.install("grpcio-gcp", "-c", constraints_path) default(session) diff --git a/setup.py b/setup.py index 576363a5..30adb954 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ "protobuf >= 3.12.0", "google-auth >= 1.21.1, < 2.0dev", "requests >= 2.18.0, < 3.0.0dev", - "setuptools >= 34.0.0", + "setuptools >= 40.3.0", "six >= 1.13.0", "pytz", 'futures >= 3.2.0; python_version < "3.2"', diff --git a/testing/constraints-2.7.txt b/testing/constraints-2.7.txt new file mode 100644 index 00000000..e69de29b diff --git a/testing/constraints-3.10.txt b/testing/constraints-3.10.txt new file mode 100644 index 00000000..e69de29b diff --git a/testing/constraints-3.11.txt b/testing/constraints-3.11.txt new file mode 100644 index 00000000..e69de29b diff --git a/testing/constraints-3.6.txt b/testing/constraints-3.6.txt new file mode 100644 index 00000000..2d498173 --- /dev/null +++ b/testing/constraints-3.6.txt @@ -0,0 +1,16 @@ +# This constraints file is used to check that lower bounds +# are correct in setup.py +# List *all* library dependencies and extras in this file. +# Pin the version to the lower bound. +# +# e.g., if setup.py has "foo >= 1.14.0, < 2.0.0dev", +# Then this file should have foo==1.14.0 +googleapis-common-protos==1.6.0 +protobuf==3.12.0 +google-auth==1.21.1 +requests==2.18.0 +setuptools==40.3.0 +six==1.13.0 +grpcio==1.29.0 +grpcio-gcp==0.2.2 +grpcio-gcp==0.2.2 diff --git a/testing/constraints-3.7.txt b/testing/constraints-3.7.txt new file mode 100644 index 00000000..e69de29b diff --git a/testing/constraints-3.8.txt b/testing/constraints-3.8.txt new file mode 100644 index 00000000..e69de29b diff --git a/testing/constraints-3.9.txt b/testing/constraints-3.9.txt new file mode 100644 index 00000000..e69de29b From 73854e897b885e9be290f2676a8a1466b4f041e4 Mon Sep 17 00:00:00 2001 From: Bu Sun Kim <8822365+busunkim96@users.noreply.github.com> Date: Thu, 14 Jan 2021 14:22:58 -0700 Subject: [PATCH 4/6] feat: allow gRPC metadata to be passed to operations client (#127) --- google/api_core/operation.py | 16 +++++---- google/api_core/operation_async.py | 8 +++-- .../operations_v1/operations_async_client.py | 35 +++++++++++++++---- .../operations_v1/operations_client.py | 35 +++++++++++++++---- .../test_operations_async_client.py | 12 ++++--- tests/asyncio/test_operation_async.py | 3 ++ .../operations_v1/test_operations_client.py | 12 ++++--- tests/unit/test_operation.py | 6 ++++ 8 files changed, 96 insertions(+), 31 deletions(-) diff --git a/google/api_core/operation.py b/google/api_core/operation.py index 9af9c4e6..a806523d 100644 --- a/google/api_core/operation.py +++ b/google/api_core/operation.py @@ -287,7 +287,7 @@ def _cancel_grpc(operations_stub, operation_name): operations_stub.CancelOperation(request_pb) -def from_grpc(operation, operations_stub, result_type, **kwargs): +def from_grpc(operation, operations_stub, result_type, grpc_metadata=None, **kwargs): """Create an operation future using a gRPC client. This interacts with the long-running operations `service`_ (specific @@ -302,18 +302,20 @@ def from_grpc(operation, operations_stub, result_type, **kwargs): operations_stub (google.longrunning.operations_pb2.OperationsStub): The operations stub. result_type (:func:`type`): The protobuf result type. + grpc_metadata (Optional[List[Tuple[str, str]]]): Additional metadata to pass + to the rpc. kwargs: Keyword args passed into the :class:`Operation` constructor. Returns: ~.api_core.operation.Operation: The operation future to track the given operation. """ - refresh = functools.partial(_refresh_grpc, operations_stub, operation.name) - cancel = functools.partial(_cancel_grpc, operations_stub, operation.name) + refresh = functools.partial(_refresh_grpc, operations_stub, operation.name, metadata=grpc_metadata) + cancel = functools.partial(_cancel_grpc, operations_stub, operation.name, metadata=grpc_metadata) return Operation(operation, refresh, cancel, result_type, **kwargs) -def from_gapic(operation, operations_client, result_type, **kwargs): +def from_gapic(operation, operations_client, result_type, grpc_metadata=None, **kwargs): """Create an operation future from a gapic client. This interacts with the long-running operations `service`_ (specific @@ -328,12 +330,14 @@ def from_gapic(operation, operations_client, result_type, **kwargs): operations_client (google.api_core.operations_v1.OperationsClient): The operations client. result_type (:func:`type`): The protobuf result type. + grpc_metadata (Optional[List[Tuple[str, str]]]): Additional metadata to pass + to the rpc. kwargs: Keyword args passed into the :class:`Operation` constructor. Returns: ~.api_core.operation.Operation: The operation future to track the given operation. """ - refresh = functools.partial(operations_client.get_operation, operation.name) - cancel = functools.partial(operations_client.cancel_operation, operation.name) + refresh = functools.partial(operations_client.get_operation, operation.name, metadata=grpc_metadata) + cancel = functools.partial(operations_client.cancel_operation, operation.name, metadata=grpc_metadata) return Operation(operation, refresh, cancel, result_type, **kwargs) diff --git a/google/api_core/operation_async.py b/google/api_core/operation_async.py index 89500af1..b137235b 100644 --- a/google/api_core/operation_async.py +++ b/google/api_core/operation_async.py @@ -189,7 +189,7 @@ async def cancelled(self): ) -def from_gapic(operation, operations_client, result_type, **kwargs): +def from_gapic(operation, operations_client, result_type, grpc_metadata=None, **kwargs): """Create an operation future from a gapic client. This interacts with the long-running operations `service`_ (specific @@ -204,12 +204,14 @@ def from_gapic(operation, operations_client, result_type, **kwargs): operations_client (google.api_core.operations_v1.OperationsClient): The operations client. result_type (:func:`type`): The protobuf result type. + grpc_metadata (Optional[List[Tuple[str, str]]]): Additional metadata to pass + to the rpc. kwargs: Keyword args passed into the :class:`Operation` constructor. Returns: ~.api_core.operation.Operation: The operation future to track the given operation. """ - refresh = functools.partial(operations_client.get_operation, operation.name) - cancel = functools.partial(operations_client.cancel_operation, operation.name) + refresh = functools.partial(operations_client.get_operation, operation.name, metadata=grpc_metadata) + cancel = functools.partial(operations_client.cancel_operation, operation.name, metadata=grpc_metadata) return AsyncOperation(operation, refresh, cancel, result_type, **kwargs) diff --git a/google/api_core/operations_v1/operations_async_client.py b/google/api_core/operations_v1/operations_async_client.py index 039bec1b..5d7b26cf 100644 --- a/google/api_core/operations_v1/operations_async_client.py +++ b/google/api_core/operations_v1/operations_async_client.py @@ -77,7 +77,11 @@ def __init__(self, channel, client_config=operations_client_config.config): ) async def get_operation( - self, name, retry=gapic_v1.method_async.DEFAULT, timeout=gapic_v1.method_async.DEFAULT + self, + name, + retry=gapic_v1.method_async.DEFAULT, + timeout=gapic_v1.method_async.DEFAULT, + metadata=None, ): """Gets the latest state of a long-running operation. @@ -103,6 +107,8 @@ async def get_operation( unspecified, the the default timeout in the client configuration is used. If ``None``, then the RPC method will not time out. + metadata (Optional[List[Tuple[str, str]]]): + Additional gRPC metadata. Returns: google.longrunning.operations_pb2.Operation: The state of the @@ -114,7 +120,7 @@ async def get_operation( subclass will be raised. """ request = operations_pb2.GetOperationRequest(name=name) - return await self._get_operation(request, retry=retry, timeout=timeout) + return await self._get_operation(request, retry=retry, timeout=timeout, metadata=metadata) async def list_operations( self, @@ -122,6 +128,7 @@ async def list_operations( filter_, retry=gapic_v1.method_async.DEFAULT, timeout=gapic_v1.method_async.DEFAULT, + metadata=None, ): """ Lists operations that match the specified filter in the request. @@ -157,6 +164,8 @@ async def list_operations( unspecified, the the default timeout in the client configuration is used. If ``None``, then the RPC method will not time out. + metadata (Optional[List[Tuple[str, str]]]): Additional gRPC + metadata. Returns: google.api_core.page_iterator.Iterator: An iterator that yields @@ -174,7 +183,7 @@ async def list_operations( request = operations_pb2.ListOperationsRequest(name=name, filter=filter_) # Create the method used to fetch pages - method = functools.partial(self._list_operations, retry=retry, timeout=timeout) + method = functools.partial(self._list_operations, retry=retry, timeout=timeout, metadata=metadata) iterator = page_iterator_async.AsyncGRPCIterator( client=None, @@ -188,7 +197,11 @@ async def list_operations( return iterator async def cancel_operation( - self, name, retry=gapic_v1.method_async.DEFAULT, timeout=gapic_v1.method_async.DEFAULT + self, + name, + retry=gapic_v1.method_async.DEFAULT, + timeout=gapic_v1.method_async.DEFAULT, + metadata=None, ): """Starts asynchronous cancellation on a long-running operation. @@ -228,13 +241,19 @@ async def cancel_operation( google.api_core.exceptions.GoogleAPICallError: If an error occurred while invoking the RPC, the appropriate ``GoogleAPICallError`` subclass will be raised. + metadata (Optional[List[Tuple[str, str]]]): Additional gRPC + metadata. """ # Create the request object. request = operations_pb2.CancelOperationRequest(name=name) - await self._cancel_operation(request, retry=retry, timeout=timeout) + await self._cancel_operation(request, retry=retry, timeout=timeout, metadata=metadata) async def delete_operation( - self, name, retry=gapic_v1.method_async.DEFAULT, timeout=gapic_v1.method_async.DEFAULT + self, + name, + retry=gapic_v1.method_async.DEFAULT, + timeout=gapic_v1.method_async.DEFAULT, + metadata=None, ): """Deletes a long-running operation. @@ -260,6 +279,8 @@ async def delete_operation( unspecified, the the default timeout in the client configuration is used. If ``None``, then the RPC method will not time out. + metadata (Optional[List[Tuple[str, str]]]): Additional gRPC + metadata. Raises: google.api_core.exceptions.MethodNotImplemented: If the server @@ -271,4 +292,4 @@ async def delete_operation( """ # Create the request object. request = operations_pb2.DeleteOperationRequest(name=name) - await self._delete_operation(request, retry=retry, timeout=timeout) + await self._delete_operation(request, retry=retry, timeout=timeout, metadata=metadata) diff --git a/google/api_core/operations_v1/operations_client.py b/google/api_core/operations_v1/operations_client.py index cd2923bb..b8507964 100644 --- a/google/api_core/operations_v1/operations_client.py +++ b/google/api_core/operations_v1/operations_client.py @@ -91,7 +91,11 @@ def __init__(self, channel, client_config=operations_client_config.config): # Service calls def get_operation( - self, name, retry=gapic_v1.method.DEFAULT, timeout=gapic_v1.method.DEFAULT + self, + name, + retry=gapic_v1.method.DEFAULT, + timeout=gapic_v1.method.DEFAULT, + metadata=None, ): """Gets the latest state of a long-running operation. @@ -117,6 +121,8 @@ def get_operation( unspecified, the the default timeout in the client configuration is used. If ``None``, then the RPC method will not time out. + metadata (Optional[List[Tuple[str, str]]]): + Additional gRPC metadata. Returns: google.longrunning.operations_pb2.Operation: The state of the @@ -128,7 +134,7 @@ def get_operation( subclass will be raised. """ request = operations_pb2.GetOperationRequest(name=name) - return self._get_operation(request, retry=retry, timeout=timeout) + return self._get_operation(request, retry=retry, timeout=timeout, metadata=metadata) def list_operations( self, @@ -136,6 +142,7 @@ def list_operations( filter_, retry=gapic_v1.method.DEFAULT, timeout=gapic_v1.method.DEFAULT, + metadata=None, ): """ Lists operations that match the specified filter in the request. @@ -171,6 +178,8 @@ def list_operations( unspecified, the the default timeout in the client configuration is used. If ``None``, then the RPC method will not time out. + metadata (Optional[List[Tuple[str, str]]]): Additional gRPC + metadata. Returns: google.api_core.page_iterator.Iterator: An iterator that yields @@ -188,7 +197,7 @@ def list_operations( request = operations_pb2.ListOperationsRequest(name=name, filter=filter_) # Create the method used to fetch pages - method = functools.partial(self._list_operations, retry=retry, timeout=timeout) + method = functools.partial(self._list_operations, retry=retry, timeout=timeout, metadata=metadata) iterator = page_iterator.GRPCIterator( client=None, @@ -202,7 +211,11 @@ def list_operations( return iterator def cancel_operation( - self, name, retry=gapic_v1.method.DEFAULT, timeout=gapic_v1.method.DEFAULT + self, + name, + retry=gapic_v1.method.DEFAULT, + timeout=gapic_v1.method.DEFAULT, + metadata=None, ): """Starts asynchronous cancellation on a long-running operation. @@ -234,6 +247,8 @@ def cancel_operation( unspecified, the the default timeout in the client configuration is used. If ``None``, then the RPC method will not time out. + metadata (Optional[List[Tuple[str, str]]]): Additional gRPC + metadata. Raises: google.api_core.exceptions.MethodNotImplemented: If the server @@ -245,10 +260,14 @@ def cancel_operation( """ # Create the request object. request = operations_pb2.CancelOperationRequest(name=name) - self._cancel_operation(request, retry=retry, timeout=timeout) + self._cancel_operation(request, retry=retry, timeout=timeout, metadata=metadata) def delete_operation( - self, name, retry=gapic_v1.method.DEFAULT, timeout=gapic_v1.method.DEFAULT + self, + name, + retry=gapic_v1.method.DEFAULT, + timeout=gapic_v1.method.DEFAULT, + metadata=None, ): """Deletes a long-running operation. @@ -274,6 +293,8 @@ def delete_operation( unspecified, the the default timeout in the client configuration is used. If ``None``, then the RPC method will not time out. + metadata (Optional[List[Tuple[str, str]]]): Additional gRPC + metadata. Raises: google.api_core.exceptions.MethodNotImplemented: If the server @@ -285,4 +306,4 @@ def delete_operation( """ # Create the request object. request = operations_pb2.DeleteOperationRequest(name=name) - self._delete_operation(request, retry=retry, timeout=timeout) + self._delete_operation(request, retry=retry, timeout=timeout, metadata=metadata) diff --git a/tests/asyncio/operations_v1/test_operations_async_client.py b/tests/asyncio/operations_v1/test_operations_async_client.py index 0f9363ff..830cd465 100644 --- a/tests/asyncio/operations_v1/test_operations_async_client.py +++ b/tests/asyncio/operations_v1/test_operations_async_client.py @@ -36,9 +36,10 @@ async def test_get_operation(): operations_pb2.Operation(name="meep")) client = operations_v1.OperationsAsyncClient(mocked_channel) - response = await client.get_operation("name") + response = await client.get_operation("name", metadata=[("x-goog-request-params", "foo")]) assert method.call_count == 1 assert tuple(method.call_args_list[0])[0][0].name == "name" + assert ("x-goog-request-params", "foo") in tuple(method.call_args_list[0])[1]["metadata"] assert response == fake_call.response @@ -53,7 +54,7 @@ async def test_list_operations(): mocked_channel, method, fake_call = _mock_grpc_objects(list_response) client = operations_v1.OperationsAsyncClient(mocked_channel) - pager = await client.list_operations("name", "filter") + pager = await client.list_operations("name", "filter", metadata=[("x-goog-request-params", "foo")]) assert isinstance(pager, page_iterator_async.AsyncIterator) responses = [] @@ -63,6 +64,7 @@ async def test_list_operations(): assert responses == operations assert method.call_count == 1 + assert ("x-goog-request-params", "foo") in tuple(method.call_args_list[0])[1]["metadata"] request = tuple(method.call_args_list[0])[0][0] assert isinstance(request, operations_pb2.ListOperationsRequest) assert request.name == "name" @@ -75,10 +77,11 @@ async def test_delete_operation(): empty_pb2.Empty()) client = operations_v1.OperationsAsyncClient(mocked_channel) - await client.delete_operation("name") + await client.delete_operation("name", metadata=[("x-goog-request-params", "foo")]) assert method.call_count == 1 assert tuple(method.call_args_list[0])[0][0].name == "name" + assert ("x-goog-request-params", "foo") in tuple(method.call_args_list[0])[1]["metadata"] @pytest.mark.asyncio @@ -87,7 +90,8 @@ async def test_cancel_operation(): empty_pb2.Empty()) client = operations_v1.OperationsAsyncClient(mocked_channel) - await client.cancel_operation("name") + await client.cancel_operation("name", metadata=[("x-goog-request-params", "foo")]) assert method.call_count == 1 assert tuple(method.call_args_list[0])[0][0].name == "name" + assert ("x-goog-request-params", "foo") in tuple(method.call_args_list[0])[1]["metadata"] diff --git a/tests/asyncio/test_operation_async.py b/tests/asyncio/test_operation_async.py index 419749f3..e35d1396 100644 --- a/tests/asyncio/test_operation_async.py +++ b/tests/asyncio/test_operation_async.py @@ -177,12 +177,15 @@ def test_from_gapic(): operations_client, struct_pb2.Struct, metadata_type=struct_pb2.Struct, + grpc_metadata=[('x-goog-request-params', 'foo')] ) assert future._result_type == struct_pb2.Struct assert future._metadata_type == struct_pb2.Struct assert future.operation.name == TEST_OPERATION_NAME assert future.done + assert future._refresh.keywords["metadata"] == [('x-goog-request-params', 'foo')] + assert future._cancel.keywords["metadata"] == [('x-goog-request-params', 'foo')] def test_deserialize(): diff --git a/tests/unit/operations_v1/test_operations_client.py b/tests/unit/operations_v1/test_operations_client.py index cc574612..bd7f3736 100644 --- a/tests/unit/operations_v1/test_operations_client.py +++ b/tests/unit/operations_v1/test_operations_client.py @@ -24,8 +24,9 @@ def test_get_operation(): client = operations_v1.OperationsClient(channel) channel.GetOperation.response = operations_pb2.Operation(name="meep") - response = client.get_operation("name") + response = client.get_operation("name", metadata=[("x-goog-request-params", "foo")]) + assert ("x-goog-request-params", "foo") in channel.GetOperation.calls[0].metadata assert len(channel.GetOperation.requests) == 1 assert channel.GetOperation.requests[0].name == "name" assert response == channel.GetOperation.response @@ -41,11 +42,12 @@ def test_list_operations(): list_response = operations_pb2.ListOperationsResponse(operations=operations) channel.ListOperations.response = list_response - response = client.list_operations("name", "filter") + response = client.list_operations("name", "filter", metadata=[("x-goog-request-params", "foo")]) assert isinstance(response, page_iterator.Iterator) assert list(response) == operations + assert ("x-goog-request-params", "foo") in channel.ListOperations.calls[0].metadata assert len(channel.ListOperations.requests) == 1 request = channel.ListOperations.requests[0] assert isinstance(request, operations_pb2.ListOperationsRequest) @@ -58,8 +60,9 @@ def test_delete_operation(): client = operations_v1.OperationsClient(channel) channel.DeleteOperation.response = empty_pb2.Empty() - client.delete_operation("name") + client.delete_operation("name", metadata=[("x-goog-request-params", "foo")]) + assert ("x-goog-request-params", "foo") in channel.DeleteOperation.calls[0].metadata assert len(channel.DeleteOperation.requests) == 1 assert channel.DeleteOperation.requests[0].name == "name" @@ -69,7 +72,8 @@ def test_cancel_operation(): client = operations_v1.OperationsClient(channel) channel.CancelOperation.response = empty_pb2.Empty() - client.cancel_operation("name") + client.cancel_operation("name", metadata=[("x-goog-request-params", "foo")]) + assert ("x-goog-request-params", "foo") in channel.CancelOperation.calls[0].metadata assert len(channel.CancelOperation.requests) == 1 assert channel.CancelOperation.requests[0].name == "name" diff --git a/tests/unit/test_operation.py b/tests/unit/test_operation.py index 2229c2d4..ae9bafea 100644 --- a/tests/unit/test_operation.py +++ b/tests/unit/test_operation.py @@ -279,12 +279,15 @@ def test_from_grpc(): operations_stub, struct_pb2.Struct, metadata_type=struct_pb2.Struct, + grpc_metadata=[('x-goog-request-params', 'foo')] ) assert future._result_type == struct_pb2.Struct assert future._metadata_type == struct_pb2.Struct assert future.operation.name == TEST_OPERATION_NAME assert future.done + assert future._refresh.keywords["metadata"] == [('x-goog-request-params', 'foo')] + assert future._cancel.keywords["metadata"] == [('x-goog-request-params', 'foo')] def test_from_gapic(): @@ -298,12 +301,15 @@ def test_from_gapic(): operations_client, struct_pb2.Struct, metadata_type=struct_pb2.Struct, + grpc_metadata=[('x-goog-request-params', 'foo')] ) assert future._result_type == struct_pb2.Struct assert future._metadata_type == struct_pb2.Struct assert future.operation.name == TEST_OPERATION_NAME assert future.done + assert future._refresh.keywords["metadata"] == [('x-goog-request-params', 'foo')] + assert future._cancel.keywords["metadata"] == [('x-goog-request-params', 'foo')] def test_deserialize(): From abc3d88466a1e55cf459e6c78a6fb7343a29df6f Mon Sep 17 00:00:00 2001 From: Tres Seaver Date: Thu, 14 Jan 2021 16:23:53 -0500 Subject: [PATCH 5/6] chore: force next release to 1.25.0 (#126) Dropped Python 3.5 support should be semver minor, not patch. Empty commit just to tweak the release bot. Release-As: 1.25.0 From 30211b4a8c6a1979ed9c67c129792ccd80128b45 Mon Sep 17 00:00:00 2001 From: "release-please[bot]" <55107282+release-please[bot]@users.noreply.github.com> Date: Thu, 14 Jan 2021 14:47:29 -0700 Subject: [PATCH 6/6] chore: release 1.25.0 (#128) Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com> --- CHANGELOG.md | 12 ++++++++++++ google/api_core/version.py | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bf420a4..d7a70077 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ [1]: https://pypi.org/project/google-api-core/#history +## [1.25.0](https://www.github.com/googleapis/python-api-core/compare/v1.24.1...v1.25.0) (2021-01-14) + + +### Features + +* allow gRPC metadata to be passed to operations client ([#127](https://www.github.com/googleapis/python-api-core/issues/127)) ([73854e8](https://www.github.com/googleapis/python-api-core/commit/73854e897b885e9be290f2676a8a1466b4f041e4)) + + +### Documentation + +* **python:** document adding Python 3.9 support, dropping 3.5 support ([#120](https://www.github.com/googleapis/python-api-core/issues/120)) ([b51b7f5](https://www.github.com/googleapis/python-api-core/commit/b51b7f587042fe9340371c1b5c8e9adf8001c43a)), closes [#787](https://www.github.com/googleapis/python-api-core/issues/787) + ### [1.24.1](https://www.github.com/googleapis/python-api-core/compare/v1.24.0...v1.24.1) (2020-12-16) diff --git a/google/api_core/version.py b/google/api_core/version.py index 10f4d5b9..327a56e2 100644 --- a/google/api_core/version.py +++ b/google/api_core/version.py @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -__version__ = "1.24.1" +__version__ = "1.25.0"