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

Skip to content

Commit eb78445

Browse files
committed
feat: Add OperationsRestAsyncTransport to support long running operations
1 parent 3f26e81 commit eb78445

File tree

7 files changed

+572
-58
lines changed

7 files changed

+572
-58
lines changed

google/api_core/operations_v1/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,22 @@
2121
from google.api_core.operations_v1.operations_client import OperationsClient
2222
from google.api_core.operations_v1.transports.rest import OperationsRestTransport
2323

24+
try:
25+
from google.api_core.operations_v1.transports.rest_asyncio import (
26+
OperationsRestAsyncTransport,
27+
)
28+
29+
HAS_ASYNC_TRANSPORT = True
30+
except ImportError:
31+
# This import requires the `async_rest` extra
32+
# Don't raise an exception if `OperationsRestAsyncTransport` cannot be imported
33+
# as other transports are still available
34+
HAS_ASYNC_TRANSPORT = False
35+
2436
__all__ = [
2537
"AbstractOperationsClient",
2638
"OperationsAsyncClient",
2739
"OperationsClient",
2840
"OperationsRestTransport",
41+
"OperationsRestAsyncTransport",
2942
]

google/api_core/operations_v1/transports/__init__.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,25 @@
1818
from .base import OperationsTransport
1919
from .rest import OperationsRestTransport
2020

21+
try:
22+
from .rest_asyncio import OperationsRestAsyncTransport
23+
24+
HAS_ASYNC_TRANSPORT = True
25+
except ImportError:
26+
# This import requires the `async_rest` extra
27+
# Don't raise an exception if `OperationsRestAsyncTransport` cannot be imported
28+
# as other transports are still available
29+
HAS_ASYNC_TRANSPORT = False
2130

2231
# Compile a registry of transports.
2332
_transport_registry = OrderedDict()
2433
_transport_registry["rest"] = OperationsRestTransport
2534

35+
if HAS_ASYNC_TRANSPORT:
36+
_transport_registry["rest_asyncio"] = OperationsRestAsyncTransport
37+
2638
__all__ = (
2739
"OperationsTransport",
2840
"OperationsRestTransport",
41+
"OperationsRestAsyncTransport",
2942
)

google/api_core/operations_v1/transports/base.py

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,26 @@
1414
# limitations under the License.
1515
#
1616
import abc
17+
import re
1718
from typing import Awaitable, Callable, Optional, Sequence, Union
1819

1920
import google.api_core # type: ignore
2021
from google.api_core import exceptions as core_exceptions # type: ignore
2122
from google.api_core import gapic_v1 # type: ignore
2223
from google.api_core import retry as retries # type: ignore
24+
from google.api_core import retry_async as retries_async # type: ignore
2325
from google.api_core import version
2426
import google.auth # type: ignore
2527
from google.auth import credentials as ga_credentials # type: ignore
2628
from google.longrunning import operations_pb2
2729
from google.oauth2 import service_account # type: ignore
28-
from google.protobuf import empty_pb2 # type: ignore
30+
import google.protobuf
31+
from google.protobuf import empty_pb2, json_format # type: ignore
2932
from grpc import Compression
3033

3134

35+
PROTOBUF_VERSION = google.protobuf.__version__
36+
3237
DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo(
3338
gapic_version=version.__version__,
3439
)
@@ -51,6 +56,7 @@ def __init__(
5156
quota_project_id: Optional[str] = None,
5257
client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO,
5358
always_use_jwt_access: Optional[bool] = False,
59+
url_scheme="https",
5460
**kwargs,
5561
) -> None:
5662
"""Instantiate the transport.
@@ -76,7 +82,20 @@ def __init__(
7682
your own client library.
7783
always_use_jwt_access (Optional[bool]): Whether self signed JWT should
7884
be used for service account credentials.
85+
url_scheme: the protocol scheme for the API endpoint. Normally
86+
"https", but for testing or local servers,
87+
"http" can be specified.
7988
"""
89+
maybe_url_match = re.match("^(?P<scheme>http(?:s)?://)?(?P<host>.*)$", host)
90+
if maybe_url_match is None:
91+
raise ValueError(
92+
f"Unexpected hostname structure: {host}"
93+
) # pragma: NO COVER
94+
95+
url_match_items = maybe_url_match.groupdict()
96+
97+
host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host
98+
8099
# Save the hostname. Default to port 443 (HTTPS) if none is specified.
81100
if ":" not in host:
82101
host += ":443"
@@ -115,12 +134,13 @@ def __init__(
115134
# Save the credentials.
116135
self._credentials = credentials
117136

118-
def _prep_wrapped_messages(self, client_info):
137+
def _prep_wrapped_messages(self, client_info, is_async=False):
119138
# Precompute the wrapped methods.
139+
retry_class = retries_async.AsyncRetry if is_async else retries.Retry
120140
self._wrapped_methods = {
121141
self.list_operations: gapic_v1.method.wrap_method(
122142
self.list_operations,
123-
default_retry=retries.Retry(
143+
default_retry=retry_class(
124144
initial=0.5,
125145
maximum=10.0,
126146
multiplier=2.0,
@@ -135,7 +155,7 @@ def _prep_wrapped_messages(self, client_info):
135155
),
136156
self.get_operation: gapic_v1.method.wrap_method(
137157
self.get_operation,
138-
default_retry=retries.Retry(
158+
default_retry=retry_class(
139159
initial=0.5,
140160
maximum=10.0,
141161
multiplier=2.0,
@@ -150,7 +170,7 @@ def _prep_wrapped_messages(self, client_info):
150170
),
151171
self.delete_operation: gapic_v1.method.wrap_method(
152172
self.delete_operation,
153-
default_retry=retries.Retry(
173+
default_retry=retry_class(
154174
initial=0.5,
155175
maximum=10.0,
156176
multiplier=2.0,
@@ -165,7 +185,7 @@ def _prep_wrapped_messages(self, client_info):
165185
),
166186
self.cancel_operation: gapic_v1.method.wrap_method(
167187
self.cancel_operation,
168-
default_retry=retries.Retry(
188+
default_retry=retry_class(
169189
initial=0.5,
170190
maximum=10.0,
171191
multiplier=2.0,
@@ -189,6 +209,38 @@ def close(self):
189209
"""
190210
raise NotImplementedError()
191211

212+
def _convert_protobuf_message_to_dict(
213+
self, message: google.protobuf.message.Message
214+
):
215+
r"""Converts protobuf message to a dictionary.
216+
217+
When the dictionary is encoded to JSON, it conforms to proto3 JSON spec.
218+
219+
Args:
220+
message(google.protobuf.message.Message): The protocol buffers message
221+
instance to serialize.
222+
223+
Returns:
224+
A dict representation of the protocol buffer message.
225+
"""
226+
# For backwards compatibility with protobuf 3.x 4.x
227+
# Remove once support for protobuf 3.x and 4.x is dropped
228+
# https://github.com/googleapis/python-api-core/issues/643
229+
if PROTOBUF_VERSION[0:2] in ["3.", "4."]:
230+
result = json_format.MessageToDict(
231+
message,
232+
preserving_proto_field_name=True,
233+
including_default_value_fields=True, # type: ignore # backward compatibility
234+
)
235+
else:
236+
result = json_format.MessageToDict(
237+
message,
238+
preserving_proto_field_name=True,
239+
always_print_fields_with_no_presence=True,
240+
)
241+
242+
return result
243+
192244
@property
193245
def list_operations(
194246
self,

google/api_core/operations_v1/transports/rest.py

Lines changed: 0 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -123,16 +123,6 @@ def __init__(
123123
# TODO(yon-mg): resolve other ctor params i.e. scopes, quota, etc.
124124
# TODO: When custom host (api_endpoint) is set, `scopes` must *also* be set on the
125125
# credentials object
126-
maybe_url_match = re.match("^(?P<scheme>http(?:s)?://)?(?P<host>.*)$", host)
127-
if maybe_url_match is None:
128-
raise ValueError(
129-
f"Unexpected hostname structure: {host}"
130-
) # pragma: NO COVER
131-
132-
url_match_items = maybe_url_match.groupdict()
133-
134-
host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host
135-
136126
super().__init__(
137127
host=host,
138128
credentials=credentials,
@@ -441,38 +431,6 @@ def _cancel_operation(
441431

442432
return empty_pb2.Empty()
443433

444-
def _convert_protobuf_message_to_dict(
445-
self, message: google.protobuf.message.Message
446-
):
447-
r"""Converts protobuf message to a dictionary.
448-
449-
When the dictionary is encoded to JSON, it conforms to proto3 JSON spec.
450-
451-
Args:
452-
message(google.protobuf.message.Message): The protocol buffers message
453-
instance to serialize.
454-
455-
Returns:
456-
A dict representation of the protocol buffer message.
457-
"""
458-
# For backwards compatibility with protobuf 3.x 4.x
459-
# Remove once support for protobuf 3.x and 4.x is dropped
460-
# https://github.com/googleapis/python-api-core/issues/643
461-
if PROTOBUF_VERSION[0:2] in ["3.", "4."]:
462-
result = json_format.MessageToDict(
463-
message,
464-
preserving_proto_field_name=True,
465-
including_default_value_fields=True, # type: ignore # backward compatibility
466-
)
467-
else:
468-
result = json_format.MessageToDict(
469-
message,
470-
preserving_proto_field_name=True,
471-
always_print_fields_with_no_presence=True,
472-
)
473-
474-
return result
475-
476434
@property
477435
def list_operations(
478436
self,

0 commit comments

Comments
 (0)