Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/google/api_core/operations_v1/transports/base.py: 54%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

65 statements  

1# -*- coding: utf-8 -*- 

2# Copyright 2020 Google LLC 

3# 

4# Licensed under the Apache License, Version 2.0 (the "License"); 

5# you may not use this file except in compliance with the License. 

6# You may obtain a copy of the License at 

7# 

8# http://www.apache.org/licenses/LICENSE-2.0 

9# 

10# Unless required by applicable law or agreed to in writing, software 

11# distributed under the License is distributed on an "AS IS" BASIS, 

12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 

13# See the License for the specific language governing permissions and 

14# limitations under the License. 

15# 

16import abc 

17import re 

18from typing import Awaitable, Callable, Optional, Sequence, Union 

19import warnings 

20 

21import google.auth # type: ignore 

22from google.auth import credentials as ga_credentials # type: ignore 

23from google.longrunning import operations_pb2 

24from google.oauth2 import service_account # type: ignore 

25import google.protobuf 

26from google.protobuf import empty_pb2, json_format # type: ignore 

27from grpc import Compression 

28 

29import google.api_core # type: ignore 

30from google.api_core import exceptions as core_exceptions # type: ignore 

31from google.api_core import gapic_v1 # type: ignore 

32from google.api_core import general_helpers 

33from google.api_core import retry as retries # type: ignore 

34from google.api_core import version 

35 

36PROTOBUF_VERSION = google.protobuf.__version__ 

37 

38DEFAULT_CLIENT_INFO = gapic_v1.client_info.ClientInfo( 

39 gapic_version=version.__version__, 

40) 

41 

42 

43class OperationsTransport(abc.ABC): 

44 """Abstract transport class for Operations.""" 

45 

46 AUTH_SCOPES = () 

47 

48 DEFAULT_HOST: str = "longrunning.googleapis.com" 

49 

50 def __init__( 

51 self, 

52 *, 

53 host: str = DEFAULT_HOST, 

54 # TODO(https://github.com/googleapis/python-api-core/issues/709): update type hint for credentials to include `google.auth.aio.Credentials`. 

55 credentials: Optional[ga_credentials.Credentials] = None, 

56 credentials_file: Optional[str] = None, 

57 scopes: Optional[Sequence[str]] = None, 

58 quota_project_id: Optional[str] = None, 

59 client_info: gapic_v1.client_info.ClientInfo = DEFAULT_CLIENT_INFO, 

60 always_use_jwt_access: Optional[bool] = False, 

61 url_scheme="https", 

62 **kwargs, 

63 ) -> None: 

64 """Instantiate the transport. 

65 

66 Args: 

67 host (Optional[str]): 

68 The hostname to connect to. 

69 credentials (Optional[google.auth.credentials.Credentials]): The 

70 authorization credentials to attach to requests. These 

71 credentials identify the application to the service; if none 

72 are specified, the client will attempt to ascertain the 

73 credentials from the environment. 

74 credentials_file (Optional[str]): Deprecated. A file with credentials that can 

75 be loaded with :func:`google.auth.load_credentials_from_file`. 

76 This argument is mutually exclusive with credentials. This argument will be 

77 removed in the next major version of `google-api-core`. 

78 

79 .. warning:: 

80 Important: If you accept a credential configuration (credential JSON/File/Stream) 

81 from an external source for authentication to Google Cloud Platform, you must 

82 validate it before providing it to any Google API or client library. Providing an 

83 unvalidated credential configuration to Google APIs or libraries can compromise 

84 the security of your systems and data. For more information, refer to 

85 `Validate credential configurations from external sources`_. 

86 

87 .. _Validate credential configurations from external sources: 

88 

89 https://cloud.google.com/docs/authentication/external/externally-sourced-credentials 

90 scopes (Optional[Sequence[str]]): A list of scopes. 

91 quota_project_id (Optional[str]): An optional project to use for billing 

92 and quota. 

93 client_info (google.api_core.gapic_v1.client_info.ClientInfo): 

94 The client info used to send a user-agent string along with 

95 API requests. If ``None``, then default info will be used. 

96 Generally, you only need to set this if you're developing 

97 your own client library. 

98 always_use_jwt_access (Optional[bool]): Whether self signed JWT should 

99 be used for service account credentials. 

100 url_scheme: the protocol scheme for the API endpoint. Normally 

101 "https", but for testing or local servers, 

102 "http" can be specified. 

103 """ 

104 if credentials_file is not None: 

105 warnings.warn(general_helpers._CREDENTIALS_FILE_WARNING, DeprecationWarning) 

106 

107 maybe_url_match = re.match("^(?P<scheme>http(?:s)?://)?(?P<host>.*)$", host) 

108 if maybe_url_match is None: 

109 raise ValueError( 

110 f"Unexpected hostname structure: {host}" 

111 ) # pragma: NO COVER 

112 

113 url_match_items = maybe_url_match.groupdict() 

114 

115 host = f"{url_scheme}://{host}" if not url_match_items["scheme"] else host 

116 

117 # Save the hostname. Default to port 443 (HTTPS) if none is specified. 

118 if ":" not in host: 

119 host += ":443" # pragma: NO COVER 

120 self._host = host 

121 

122 scopes_kwargs = {"scopes": scopes, "default_scopes": self.AUTH_SCOPES} 

123 

124 # Save the scopes. 

125 self._scopes = scopes 

126 

127 # If no credentials are provided, then determine the appropriate 

128 # defaults. 

129 if credentials and credentials_file: 

130 raise core_exceptions.DuplicateCredentialArgs( 

131 "'credentials_file' and 'credentials' are mutually exclusive" 

132 ) 

133 

134 if credentials_file is not None: 

135 credentials, _ = google.auth.load_credentials_from_file( 

136 credentials_file, **scopes_kwargs, quota_project_id=quota_project_id 

137 ) 

138 

139 elif credentials is None: 

140 credentials, _ = google.auth.default( 

141 **scopes_kwargs, quota_project_id=quota_project_id 

142 ) 

143 

144 # If the credentials are service account credentials, then always try to use self signed JWT. 

145 if ( 

146 always_use_jwt_access 

147 and isinstance(credentials, service_account.Credentials) 

148 and hasattr(service_account.Credentials, "with_always_use_jwt_access") 

149 ): 

150 credentials = credentials.with_always_use_jwt_access(True) 

151 

152 # Save the credentials. 

153 self._credentials = credentials 

154 

155 def _prep_wrapped_messages(self, client_info): 

156 # Precompute the wrapped methods. 

157 self._wrapped_methods = { 

158 self.list_operations: gapic_v1.method.wrap_method( 

159 self.list_operations, 

160 default_retry=retries.Retry( 

161 initial=0.5, 

162 maximum=10.0, 

163 multiplier=2.0, 

164 predicate=retries.if_exception_type( 

165 core_exceptions.ServiceUnavailable, 

166 ), 

167 deadline=10.0, 

168 ), 

169 default_timeout=10.0, 

170 default_compression=Compression.NoCompression, 

171 client_info=client_info, 

172 ), 

173 self.get_operation: gapic_v1.method.wrap_method( 

174 self.get_operation, 

175 default_retry=retries.Retry( 

176 initial=0.5, 

177 maximum=10.0, 

178 multiplier=2.0, 

179 predicate=retries.if_exception_type( 

180 core_exceptions.ServiceUnavailable, 

181 ), 

182 deadline=10.0, 

183 ), 

184 default_timeout=10.0, 

185 default_compression=Compression.NoCompression, 

186 client_info=client_info, 

187 ), 

188 self.delete_operation: gapic_v1.method.wrap_method( 

189 self.delete_operation, 

190 default_retry=retries.Retry( 

191 initial=0.5, 

192 maximum=10.0, 

193 multiplier=2.0, 

194 predicate=retries.if_exception_type( 

195 core_exceptions.ServiceUnavailable, 

196 ), 

197 deadline=10.0, 

198 ), 

199 default_timeout=10.0, 

200 default_compression=Compression.NoCompression, 

201 client_info=client_info, 

202 ), 

203 self.cancel_operation: gapic_v1.method.wrap_method( 

204 self.cancel_operation, 

205 default_retry=retries.Retry( 

206 initial=0.5, 

207 maximum=10.0, 

208 multiplier=2.0, 

209 predicate=retries.if_exception_type( 

210 core_exceptions.ServiceUnavailable, 

211 ), 

212 deadline=10.0, 

213 ), 

214 default_timeout=10.0, 

215 default_compression=Compression.NoCompression, 

216 client_info=client_info, 

217 ), 

218 } 

219 

220 def close(self): 

221 """Closes resources associated with the transport. 

222 

223 .. warning:: 

224 Only call this method if the transport is NOT shared 

225 with other clients - this may cause errors in other clients! 

226 """ 

227 raise NotImplementedError() 

228 

229 def _convert_protobuf_message_to_dict( 

230 self, message: google.protobuf.message.Message 

231 ): 

232 r"""Converts protobuf message to a dictionary. 

233 

234 When the dictionary is encoded to JSON, it conforms to proto3 JSON spec. 

235 

236 Args: 

237 message(google.protobuf.message.Message): The protocol buffers message 

238 instance to serialize. 

239 

240 Returns: 

241 A dict representation of the protocol buffer message. 

242 """ 

243 # TODO(https://github.com/googleapis/python-api-core/issues/643): For backwards compatibility 

244 # with protobuf 3.x 4.x, Remove once support for protobuf 3.x and 4.x is dropped. 

245 if PROTOBUF_VERSION[0:2] in ["3.", "4."]: 

246 result = json_format.MessageToDict( 

247 message, 

248 preserving_proto_field_name=True, 

249 including_default_value_fields=True, # type: ignore # backward compatibility 

250 ) 

251 else: 

252 result = json_format.MessageToDict( 

253 message, 

254 preserving_proto_field_name=True, 

255 always_print_fields_with_no_presence=True, 

256 ) 

257 

258 return result 

259 

260 @property 

261 def list_operations( 

262 self, 

263 ) -> Callable[ 

264 [operations_pb2.ListOperationsRequest], 

265 Union[ 

266 operations_pb2.ListOperationsResponse, 

267 Awaitable[operations_pb2.ListOperationsResponse], 

268 ], 

269 ]: 

270 raise NotImplementedError() 

271 

272 @property 

273 def get_operation( 

274 self, 

275 ) -> Callable[ 

276 [operations_pb2.GetOperationRequest], 

277 Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], 

278 ]: 

279 raise NotImplementedError() 

280 

281 @property 

282 def delete_operation( 

283 self, 

284 ) -> Callable[ 

285 [operations_pb2.DeleteOperationRequest], 

286 Union[empty_pb2.Empty, Awaitable[empty_pb2.Empty]], 

287 ]: 

288 raise NotImplementedError() 

289 

290 @property 

291 def cancel_operation( 

292 self, 

293 ) -> Callable[ 

294 [operations_pb2.CancelOperationRequest], 

295 Union[empty_pb2.Empty, Awaitable[empty_pb2.Empty]], 

296 ]: 

297 raise NotImplementedError() 

298 

299 

300__all__ = ("OperationsTransport",)