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

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

64 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 # Save the scopes. 

123 self._scopes = scopes 

124 

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

126 # defaults. 

127 if credentials and credentials_file: 

128 raise core_exceptions.DuplicateCredentialArgs( 

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

130 ) 

131 

132 if credentials_file is not None: 

133 credentials, _ = google.auth.load_credentials_from_file( 

134 credentials_file, 

135 scopes=scopes, 

136 quota_project_id=quota_project_id, 

137 default_scopes=self.AUTH_SCOPES, 

138 ) 

139 

140 elif credentials is None: 

141 credentials, _ = google.auth.default( 

142 scopes=scopes, 

143 quota_project_id=quota_project_id, 

144 default_scopes=self.AUTH_SCOPES, 

145 ) 

146 

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

148 if ( 

149 always_use_jwt_access 

150 and isinstance(credentials, service_account.Credentials) 

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

152 ): 

153 credentials = credentials.with_always_use_jwt_access(True) 

154 

155 # Save the credentials. 

156 self._credentials = credentials 

157 

158 def _prep_wrapped_messages(self, client_info): 

159 # Precompute the wrapped methods. 

160 self._wrapped_methods = { 

161 self.list_operations: gapic_v1.method.wrap_method( 

162 self.list_operations, 

163 default_retry=retries.Retry( 

164 initial=0.5, 

165 maximum=10.0, 

166 multiplier=2.0, 

167 predicate=retries.if_exception_type( 

168 core_exceptions.ServiceUnavailable, 

169 ), 

170 deadline=10.0, 

171 ), 

172 default_timeout=10.0, 

173 default_compression=Compression.NoCompression, 

174 client_info=client_info, 

175 ), 

176 self.get_operation: gapic_v1.method.wrap_method( 

177 self.get_operation, 

178 default_retry=retries.Retry( 

179 initial=0.5, 

180 maximum=10.0, 

181 multiplier=2.0, 

182 predicate=retries.if_exception_type( 

183 core_exceptions.ServiceUnavailable, 

184 ), 

185 deadline=10.0, 

186 ), 

187 default_timeout=10.0, 

188 default_compression=Compression.NoCompression, 

189 client_info=client_info, 

190 ), 

191 self.delete_operation: gapic_v1.method.wrap_method( 

192 self.delete_operation, 

193 default_retry=retries.Retry( 

194 initial=0.5, 

195 maximum=10.0, 

196 multiplier=2.0, 

197 predicate=retries.if_exception_type( 

198 core_exceptions.ServiceUnavailable, 

199 ), 

200 deadline=10.0, 

201 ), 

202 default_timeout=10.0, 

203 default_compression=Compression.NoCompression, 

204 client_info=client_info, 

205 ), 

206 self.cancel_operation: gapic_v1.method.wrap_method( 

207 self.cancel_operation, 

208 default_retry=retries.Retry( 

209 initial=0.5, 

210 maximum=10.0, 

211 multiplier=2.0, 

212 predicate=retries.if_exception_type( 

213 core_exceptions.ServiceUnavailable, 

214 ), 

215 deadline=10.0, 

216 ), 

217 default_timeout=10.0, 

218 default_compression=Compression.NoCompression, 

219 client_info=client_info, 

220 ), 

221 } 

222 

223 def close(self): 

224 """Closes resources associated with the transport. 

225 

226 .. warning:: 

227 Only call this method if the transport is NOT shared 

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

229 """ 

230 raise NotImplementedError() 

231 

232 def _convert_protobuf_message_to_dict( 

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

234 ): 

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

236 

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

238 

239 Args: 

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

241 instance to serialize. 

242 

243 Returns: 

244 A dict representation of the protocol buffer message. 

245 """ 

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

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

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

249 result = json_format.MessageToDict( 

250 message, 

251 preserving_proto_field_name=True, 

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

253 ) 

254 else: 

255 result = json_format.MessageToDict( 

256 message, 

257 preserving_proto_field_name=True, 

258 always_print_fields_with_no_presence=True, 

259 ) 

260 

261 return result 

262 

263 @property 

264 def list_operations( 

265 self, 

266 ) -> Callable[ 

267 [operations_pb2.ListOperationsRequest], 

268 Union[ 

269 operations_pb2.ListOperationsResponse, 

270 Awaitable[operations_pb2.ListOperationsResponse], 

271 ], 

272 ]: 

273 raise NotImplementedError() 

274 

275 @property 

276 def get_operation( 

277 self, 

278 ) -> Callable[ 

279 [operations_pb2.GetOperationRequest], 

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

281 ]: 

282 raise NotImplementedError() 

283 

284 @property 

285 def delete_operation( 

286 self, 

287 ) -> Callable[ 

288 [operations_pb2.DeleteOperationRequest], 

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

290 ]: 

291 raise NotImplementedError() 

292 

293 @property 

294 def cancel_operation( 

295 self, 

296 ) -> Callable[ 

297 [operations_pb2.CancelOperationRequest], 

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

299 ]: 

300 raise NotImplementedError() 

301 

302 

303__all__ = ("OperationsTransport",)