Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/google/cloud/storage/_media/requests/upload.py: 23%

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

73 statements  

1# Copyright 2017 Google Inc. 

2# 

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

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

5# You may obtain a copy of the License at 

6# 

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

8# 

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

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

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

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

13# limitations under the License. 

14 

15"""Support for resumable uploads. 

16 

17Also supported here are simple (media) uploads and multipart 

18uploads that contain both metadata and a small file as payload. 

19""" 

20 

21 

22from google.cloud.storage._media import _upload 

23from google.cloud.storage._media.requests import _request_helpers 

24 

25 

26class SimpleUpload(_request_helpers.RequestsMixin, _upload.SimpleUpload): 

27 """Upload a resource to a Google API. 

28 

29 A **simple** media upload sends no metadata and completes the upload 

30 in a single request. 

31 

32 Args: 

33 upload_url (str): The URL where the content will be uploaded. 

34 headers (Optional[Mapping[str, str]]): Extra headers that should 

35 be sent with the request, e.g. headers for encrypted data. 

36 

37 Attributes: 

38 upload_url (str): The URL where the content will be uploaded. 

39 """ 

40 

41 def transmit( 

42 self, 

43 transport, 

44 data, 

45 content_type, 

46 timeout=( 

47 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

48 _request_helpers._DEFAULT_READ_TIMEOUT, 

49 ), 

50 ): 

51 """Transmit the resource to be uploaded. 

52 

53 Args: 

54 transport (~requests.Session): A ``requests`` object which can 

55 make authenticated requests. 

56 data (bytes): The resource content to be uploaded. 

57 content_type (str): The content type of the resource, e.g. a JPEG 

58 image has content type ``image/jpeg``. 

59 timeout (Optional[Union[float, Tuple[float, float]]]): 

60 The number of seconds to wait for the server response. 

61 Depending on the retry strategy, a request may be repeated 

62 several times using the same timeout each time. 

63 

64 Can also be passed as a tuple (connect_timeout, read_timeout). 

65 See :meth:`requests.Session.request` documentation for details. 

66 

67 Returns: 

68 ~requests.Response: The HTTP response returned by ``transport``. 

69 """ 

70 method, url, payload, headers = self._prepare_request(data, content_type) 

71 

72 # Wrap the request business logic in a function to be retried. 

73 def retriable_request(): 

74 result = transport.request( 

75 method, url, data=payload, headers=headers, timeout=timeout 

76 ) 

77 

78 self._process_response(result) 

79 

80 return result 

81 

82 return _request_helpers.wait_and_retry(retriable_request, self._retry_strategy) 

83 

84 

85class MultipartUpload(_request_helpers.RequestsMixin, _upload.MultipartUpload): 

86 """Upload a resource with metadata to a Google API. 

87 

88 A **multipart** upload sends both metadata and the resource in a single 

89 (multipart) request. 

90 

91 Args: 

92 upload_url (str): The URL where the content will be uploaded. 

93 headers (Optional[Mapping[str, str]]): Extra headers that should 

94 be sent with the request, e.g. headers for encrypted data. 

95 checksum Optional([str]): The type of checksum to compute to verify 

96 the integrity of the object. The request metadata will be amended 

97 to include the computed value. Using this option will override a 

98 manually-set checksum value. Supported values are "md5", 

99 "crc32c", "auto", and None. The default is "auto", which will try 

100 to detect if the C extension for crc32c is installed and fall back 

101 to md5 otherwise. 

102 retry (Optional[google.api_core.retry.Retry]): How to retry the 

103 RPC. A None value will disable retries. A 

104 google.api_core.retry.Retry value will enable retries, and the 

105 object will configure backoff and timeout options. 

106 

107 See the retry.py source code and docstrings in this package 

108 (google.cloud.storage.retry) for information on retry types and how 

109 to configure them. 

110 

111 Attributes: 

112 upload_url (str): The URL where the content will be uploaded. 

113 """ 

114 

115 def transmit( 

116 self, 

117 transport, 

118 data, 

119 metadata, 

120 content_type, 

121 timeout=( 

122 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

123 _request_helpers._DEFAULT_READ_TIMEOUT, 

124 ), 

125 ): 

126 """Transmit the resource to be uploaded. 

127 

128 Args: 

129 transport (~requests.Session): A ``requests`` object which can 

130 make authenticated requests. 

131 data (bytes): The resource content to be uploaded. 

132 metadata (Mapping[str, str]): The resource metadata, such as an 

133 ACL list. 

134 content_type (str): The content type of the resource, e.g. a JPEG 

135 image has content type ``image/jpeg``. 

136 timeout (Optional[Union[float, Tuple[float, float]]]): 

137 The number of seconds to wait for the server response. 

138 Depending on the retry strategy, a request may be repeated 

139 several times using the same timeout each time. 

140 

141 Can also be passed as a tuple (connect_timeout, read_timeout). 

142 See :meth:`requests.Session.request` documentation for details. 

143 

144 Returns: 

145 ~requests.Response: The HTTP response returned by ``transport``. 

146 """ 

147 method, url, payload, headers = self._prepare_request( 

148 data, metadata, content_type 

149 ) 

150 

151 # Wrap the request business logic in a function to be retried. 

152 def retriable_request(): 

153 result = transport.request( 

154 method, url, data=payload, headers=headers, timeout=timeout 

155 ) 

156 

157 self._process_response(result) 

158 

159 return result 

160 

161 return _request_helpers.wait_and_retry(retriable_request, self._retry_strategy) 

162 

163 

164class ResumableUpload(_request_helpers.RequestsMixin, _upload.ResumableUpload): 

165 """Initiate and fulfill a resumable upload to a Google API. 

166 

167 A **resumable** upload sends an initial request with the resource metadata 

168 and then gets assigned an upload ID / upload URL to send bytes to. 

169 Using the upload URL, the upload is then done in chunks (determined by 

170 the user) until all bytes have been uploaded. 

171 

172 When constructing a resumable upload, only the resumable upload URL and 

173 the chunk size are required: 

174 

175 .. testsetup:: resumable-constructor 

176 

177 bucket = 'bucket-foo' 

178 

179 .. doctest:: resumable-constructor 

180 

181 >>> from google.cloud.storage._media.requests import ResumableUpload 

182 >>> 

183 >>> url_template = ( 

184 ... 'https://www.googleapis.com/upload/storage/v1/b/{bucket}/o?' 

185 ... 'uploadType=resumable') 

186 >>> upload_url = url_template.format(bucket=bucket) 

187 >>> 

188 >>> chunk_size = 3 * 1024 * 1024 # 3MB 

189 >>> upload = ResumableUpload(upload_url, chunk_size) 

190 

191 When initiating an upload (via :meth:`initiate`), the caller is expected 

192 to pass the resource being uploaded as a file-like ``stream``. If the size 

193 of the resource is explicitly known, it can be passed in directly: 

194 

195 .. testsetup:: resumable-explicit-size 

196 

197 import os 

198 import tempfile 

199 

200 import mock 

201 import requests 

202 import http.client 

203 

204 from google.cloud.storage._media.requests import ResumableUpload 

205 

206 upload_url = 'http://test.invalid' 

207 chunk_size = 3 * 1024 * 1024 # 3MB 

208 upload = ResumableUpload(upload_url, chunk_size) 

209 

210 file_desc, filename = tempfile.mkstemp() 

211 os.close(file_desc) 

212 

213 data = b'some bytes!' 

214 with open(filename, 'wb') as file_obj: 

215 file_obj.write(data) 

216 

217 fake_response = requests.Response() 

218 fake_response.status_code = int(http.client.OK) 

219 fake_response._content = b'' 

220 resumable_url = 'http://test.invalid?upload_id=7up' 

221 fake_response.headers['location'] = resumable_url 

222 

223 post_method = mock.Mock(return_value=fake_response, spec=[]) 

224 transport = mock.Mock(request=post_method, spec=['request']) 

225 

226 .. doctest:: resumable-explicit-size 

227 

228 >>> import os 

229 >>> 

230 >>> upload.total_bytes is None 

231 True 

232 >>> 

233 >>> stream = open(filename, 'rb') 

234 >>> total_bytes = os.path.getsize(filename) 

235 >>> metadata = {'name': filename} 

236 >>> response = upload.initiate( 

237 ... transport, stream, metadata, 'text/plain', 

238 ... total_bytes=total_bytes) 

239 >>> response 

240 <Response [200]> 

241 >>> 

242 >>> upload.total_bytes == total_bytes 

243 True 

244 

245 .. testcleanup:: resumable-explicit-size 

246 

247 os.remove(filename) 

248 

249 If the stream is in a "final" state (i.e. it won't have any more bytes 

250 written to it), the total number of bytes can be determined implicitly 

251 from the ``stream`` itself: 

252 

253 .. testsetup:: resumable-implicit-size 

254 

255 import io 

256 

257 import mock 

258 import requests 

259 import http.client 

260 

261 from google.cloud.storage._media.requests import ResumableUpload 

262 

263 upload_url = 'http://test.invalid' 

264 chunk_size = 3 * 1024 * 1024 # 3MB 

265 upload = ResumableUpload(upload_url, chunk_size) 

266 

267 fake_response = requests.Response() 

268 fake_response.status_code = int(http.client.OK) 

269 fake_response._content = b'' 

270 resumable_url = 'http://test.invalid?upload_id=7up' 

271 fake_response.headers['location'] = resumable_url 

272 

273 post_method = mock.Mock(return_value=fake_response, spec=[]) 

274 transport = mock.Mock(request=post_method, spec=['request']) 

275 

276 data = b'some MOAR bytes!' 

277 metadata = {'name': 'some-file.jpg'} 

278 content_type = 'image/jpeg' 

279 

280 .. doctest:: resumable-implicit-size 

281 

282 >>> stream = io.BytesIO(data) 

283 >>> response = upload.initiate( 

284 ... transport, stream, metadata, content_type) 

285 >>> 

286 >>> upload.total_bytes == len(data) 

287 True 

288 

289 If the size of the resource is **unknown** when the upload is initiated, 

290 the ``stream_final`` argument can be used. This might occur if the 

291 resource is being dynamically created on the client (e.g. application 

292 logs). To use this argument: 

293 

294 .. testsetup:: resumable-unknown-size 

295 

296 import io 

297 

298 import mock 

299 import requests 

300 import http.client 

301 

302 from google.cloud.storage._media.requests import ResumableUpload 

303 

304 upload_url = 'http://test.invalid' 

305 chunk_size = 3 * 1024 * 1024 # 3MB 

306 upload = ResumableUpload(upload_url, chunk_size) 

307 

308 fake_response = requests.Response() 

309 fake_response.status_code = int(http.client.OK) 

310 fake_response._content = b'' 

311 resumable_url = 'http://test.invalid?upload_id=7up' 

312 fake_response.headers['location'] = resumable_url 

313 

314 post_method = mock.Mock(return_value=fake_response, spec=[]) 

315 transport = mock.Mock(request=post_method, spec=['request']) 

316 

317 metadata = {'name': 'some-file.jpg'} 

318 content_type = 'application/octet-stream' 

319 

320 stream = io.BytesIO(b'data') 

321 

322 .. doctest:: resumable-unknown-size 

323 

324 >>> response = upload.initiate( 

325 ... transport, stream, metadata, content_type, 

326 ... stream_final=False) 

327 >>> 

328 >>> upload.total_bytes is None 

329 True 

330 

331 Args: 

332 upload_url (str): The URL where the resumable upload will be initiated. 

333 chunk_size (int): The size of each chunk used to upload the resource. 

334 headers (Optional[Mapping[str, str]]): Extra headers that should 

335 be sent with the :meth:`initiate` request, e.g. headers for 

336 encrypted data. These **will not** be sent with 

337 :meth:`transmit_next_chunk` or :meth:`recover` requests. 

338 checksum Optional([str]): The type of checksum to compute to verify 

339 the integrity of the object. After the upload is complete, the 

340 server-computed checksum of the resulting object will be checked 

341 and google.cloud.storage.exceptions.DataCorruption will be raised on 

342 a mismatch. The corrupted file will not be deleted from the remote 

343 host automatically. Supported values are "md5", "crc32c", "auto", 

344 and None. The default is "auto", which will try to detect if the C 

345 extension for crc32c is installed and fall back to md5 otherwise. 

346 retry (Optional[google.api_core.retry.Retry]): How to retry the 

347 RPC. A None value will disable retries. A 

348 google.api_core.retry.Retry value will enable retries, and the 

349 object will configure backoff and timeout options. 

350 

351 See the retry.py source code and docstrings in this package 

352 (google.cloud.storage.retry) for information on retry types and how 

353 to configure them. 

354 

355 Attributes: 

356 upload_url (str): The URL where the content will be uploaded. 

357 

358 Raises: 

359 ValueError: If ``chunk_size`` is not a multiple of 

360 :data:`.UPLOAD_CHUNK_SIZE`. 

361 """ 

362 

363 def initiate( 

364 self, 

365 transport, 

366 stream, 

367 metadata, 

368 content_type, 

369 total_bytes=None, 

370 stream_final=True, 

371 timeout=( 

372 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

373 _request_helpers._DEFAULT_READ_TIMEOUT, 

374 ), 

375 ): 

376 """Initiate a resumable upload. 

377 

378 By default, this method assumes your ``stream`` is in a "final" 

379 state ready to transmit. However, ``stream_final=False`` can be used 

380 to indicate that the size of the resource is not known. This can happen 

381 if bytes are being dynamically fed into ``stream``, e.g. if the stream 

382 is attached to application logs. 

383 

384 If ``stream_final=False`` is used, :attr:`chunk_size` bytes will be 

385 read from the stream every time :meth:`transmit_next_chunk` is called. 

386 If one of those reads produces strictly fewer bites than the chunk 

387 size, the upload will be concluded. 

388 

389 Args: 

390 transport (~requests.Session): A ``requests`` object which can 

391 make authenticated requests. 

392 stream (IO[bytes]): The stream (i.e. file-like object) that will 

393 be uploaded. The stream **must** be at the beginning (i.e. 

394 ``stream.tell() == 0``). 

395 metadata (Mapping[str, str]): The resource metadata, such as an 

396 ACL list. 

397 content_type (str): The content type of the resource, e.g. a JPEG 

398 image has content type ``image/jpeg``. 

399 total_bytes (Optional[int]): The total number of bytes to be 

400 uploaded. If specified, the upload size **will not** be 

401 determined from the stream (even if ``stream_final=True``). 

402 stream_final (Optional[bool]): Indicates if the ``stream`` is 

403 "final" (i.e. no more bytes will be added to it). In this case 

404 we determine the upload size from the size of the stream. If 

405 ``total_bytes`` is passed, this argument will be ignored. 

406 timeout (Optional[Union[float, Tuple[float, float]]]): 

407 The number of seconds to wait for the server response. 

408 Depending on the retry strategy, a request may be repeated 

409 several times using the same timeout each time. 

410 

411 Can also be passed as a tuple (connect_timeout, read_timeout). 

412 See :meth:`requests.Session.request` documentation for details. 

413 

414 Returns: 

415 ~requests.Response: The HTTP response returned by ``transport``. 

416 """ 

417 method, url, payload, headers = self._prepare_initiate_request( 

418 stream, 

419 metadata, 

420 content_type, 

421 total_bytes=total_bytes, 

422 stream_final=stream_final, 

423 ) 

424 

425 # Wrap the request business logic in a function to be retried. 

426 def retriable_request(): 

427 result = transport.request( 

428 method, url, data=payload, headers=headers, timeout=timeout 

429 ) 

430 

431 self._process_initiate_response(result) 

432 

433 return result 

434 

435 return _request_helpers.wait_and_retry(retriable_request, self._retry_strategy) 

436 

437 def transmit_next_chunk( 

438 self, 

439 transport, 

440 timeout=( 

441 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

442 _request_helpers._DEFAULT_READ_TIMEOUT, 

443 ), 

444 ): 

445 """Transmit the next chunk of the resource to be uploaded. 

446 

447 If the current upload was initiated with ``stream_final=False``, 

448 this method will dynamically determine if the upload has completed. 

449 The upload will be considered complete if the stream produces 

450 fewer than :attr:`chunk_size` bytes when a chunk is read from it. 

451 

452 In the case of failure, an exception is thrown that preserves the 

453 failed response: 

454 

455 .. testsetup:: bad-response 

456 

457 import io 

458 

459 import mock 

460 import requests 

461 import http.client 

462 

463 from google.cloud.storage import _media 

464 import google.cloud.storage._media.requests.upload as upload_mod 

465 

466 transport = mock.Mock(spec=['request']) 

467 fake_response = requests.Response() 

468 fake_response.status_code = int(http.client.BAD_REQUEST) 

469 transport.request.return_value = fake_response 

470 

471 upload_url = 'http://test.invalid' 

472 upload = upload_mod.ResumableUpload( 

473 upload_url, _media.UPLOAD_CHUNK_SIZE) 

474 # Fake that the upload has been initiate()-d 

475 data = b'data is here' 

476 upload._stream = io.BytesIO(data) 

477 upload._total_bytes = len(data) 

478 upload._resumable_url = 'http://test.invalid?upload_id=nope' 

479 

480 .. doctest:: bad-response 

481 :options: +NORMALIZE_WHITESPACE 

482 

483 >>> error = None 

484 >>> try: 

485 ... upload.transmit_next_chunk(transport) 

486 ... except _media.InvalidResponse as caught_exc: 

487 ... error = caught_exc 

488 ... 

489 >>> error 

490 InvalidResponse('Request failed with status code', 400, 

491 'Expected one of', <HTTPStatus.OK: 200>, <HTTPStatus.PERMANENT_REDIRECT: 308>) 

492 >>> error.response 

493 <Response [400]> 

494 

495 Args: 

496 transport (~requests.Session): A ``requests`` object which can 

497 make authenticated requests. 

498 timeout (Optional[Union[float, Tuple[float, float]]]): 

499 The number of seconds to wait for the server response. 

500 Depending on the retry strategy, a request may be repeated 

501 several times using the same timeout each time. 

502 

503 Can also be passed as a tuple (connect_timeout, read_timeout). 

504 See :meth:`requests.Session.request` documentation for details. 

505 

506 Returns: 

507 ~requests.Response: The HTTP response returned by ``transport``. 

508 

509 Raises: 

510 ~google.cloud.storage.exceptions.InvalidResponse: If the status 

511 code is not 200 or http.client.PERMANENT_REDIRECT. 

512 ~google.cloud.storage.exceptions.DataCorruption: If this is the final 

513 chunk, a checksum validation was requested, and the checksum 

514 does not match or is not available. 

515 """ 

516 method, url, payload, headers = self._prepare_request() 

517 

518 # Wrap the request business logic in a function to be retried. 

519 def retriable_request(): 

520 result = transport.request( 

521 method, url, data=payload, headers=headers, timeout=timeout 

522 ) 

523 

524 self._process_resumable_response(result, len(payload)) 

525 

526 return result 

527 

528 return _request_helpers.wait_and_retry(retriable_request, self._retry_strategy) 

529 

530 def recover(self, transport): 

531 """Recover from a failure and check the status of the current upload. 

532 

533 This will verify the progress with the server and make sure the 

534 current upload is in a valid state before :meth:`transmit_next_chunk` 

535 can be used again. See https://cloud.google.com/storage/docs/performing-resumable-uploads#status-check 

536 for more information. 

537 

538 This method can be used when a :class:`ResumableUpload` is in an 

539 :attr:`~ResumableUpload.invalid` state due to a request failure. 

540 

541 Args: 

542 transport (~requests.Session): A ``requests`` object which can 

543 make authenticated requests. 

544 

545 Returns: 

546 ~requests.Response: The HTTP response returned by ``transport``. 

547 """ 

548 timeout = ( 

549 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

550 _request_helpers._DEFAULT_READ_TIMEOUT, 

551 ) 

552 

553 method, url, payload, headers = self._prepare_recover_request() 

554 # NOTE: We assume "payload is None" but pass it along anyway. 

555 

556 # Wrap the request business logic in a function to be retried. 

557 def retriable_request(): 

558 result = transport.request( 

559 method, url, data=payload, headers=headers, timeout=timeout 

560 ) 

561 

562 self._process_recover_response(result) 

563 

564 return result 

565 

566 return _request_helpers.wait_and_retry(retriable_request, self._retry_strategy) 

567 

568 

569class XMLMPUContainer(_request_helpers.RequestsMixin, _upload.XMLMPUContainer): 

570 """Initiate and close an upload using the XML MPU API. 

571 

572 An XML MPU sends an initial request and then receives an upload ID. 

573 Using the upload ID, the upload is then done in numbered parts and the 

574 parts can be uploaded concurrently. 

575 

576 In order to avoid concurrency issues with this container object, the 

577 uploading of individual parts is handled separately, by XMLMPUPart objects 

578 spawned from this container class. The XMLMPUPart objects are not 

579 necessarily in the same process as the container, so they do not update the 

580 container automatically. 

581 

582 MPUs are sometimes referred to as "Multipart Uploads", which is ambiguous 

583 given the JSON multipart upload, so the abbreviation "MPU" will be used 

584 throughout. 

585 

586 See: https://cloud.google.com/storage/docs/multipart-uploads 

587 

588 Args: 

589 upload_url (str): The URL of the object (without query parameters). The 

590 initiate, PUT, and finalization requests will all use this URL, with 

591 varying query parameters. 

592 headers (Optional[Mapping[str, str]]): Extra headers that should 

593 be sent with the :meth:`initiate` request, e.g. headers for 

594 encrypted data. These headers will be propagated to individual 

595 XMLMPUPart objects spawned from this container as well. 

596 retry (Optional[google.api_core.retry.Retry]): How to retry the 

597 RPC. A None value will disable retries. A 

598 google.api_core.retry.Retry value will enable retries, and the 

599 object will configure backoff and timeout options. 

600 

601 See the retry.py source code and docstrings in this package 

602 (google.cloud.storage.retry) for information on retry types and how 

603 to configure them. 

604 

605 Attributes: 

606 upload_url (str): The URL where the content will be uploaded. 

607 upload_id (Optional(int)): The ID of the upload from the initialization 

608 response. 

609 """ 

610 

611 def initiate( 

612 self, 

613 transport, 

614 content_type, 

615 timeout=( 

616 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

617 _request_helpers._DEFAULT_READ_TIMEOUT, 

618 ), 

619 ): 

620 """Initiate an MPU and record the upload ID. 

621 

622 Args: 

623 transport (object): An object which can make authenticated 

624 requests. 

625 content_type (str): The content type of the resource, e.g. a JPEG 

626 image has content type ``image/jpeg``. 

627 timeout (Optional[Union[float, Tuple[float, float]]]): 

628 The number of seconds to wait for the server response. 

629 Depending on the retry strategy, a request may be repeated 

630 several times using the same timeout each time. 

631 

632 Can also be passed as a tuple (connect_timeout, read_timeout). 

633 See :meth:`requests.Session.request` documentation for details. 

634 

635 Returns: 

636 ~requests.Response: The HTTP response returned by ``transport``. 

637 """ 

638 

639 method, url, payload, headers = self._prepare_initiate_request( 

640 content_type, 

641 ) 

642 

643 # Wrap the request business logic in a function to be retried. 

644 def retriable_request(): 

645 result = transport.request( 

646 method, url, data=payload, headers=headers, timeout=timeout 

647 ) 

648 

649 self._process_initiate_response(result) 

650 

651 return result 

652 

653 return _request_helpers.wait_and_retry(retriable_request, self._retry_strategy) 

654 

655 def finalize( 

656 self, 

657 transport, 

658 timeout=( 

659 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

660 _request_helpers._DEFAULT_READ_TIMEOUT, 

661 ), 

662 ): 

663 """Finalize an MPU request with all the parts. 

664 

665 Args: 

666 transport (object): An object which can make authenticated 

667 requests. 

668 timeout (Optional[Union[float, Tuple[float, float]]]): 

669 The number of seconds to wait for the server response. 

670 Depending on the retry strategy, a request may be repeated 

671 several times using the same timeout each time. 

672 

673 Can also be passed as a tuple (connect_timeout, read_timeout). 

674 See :meth:`requests.Session.request` documentation for details. 

675 

676 Returns: 

677 ~requests.Response: The HTTP response returned by ``transport``. 

678 """ 

679 method, url, payload, headers = self._prepare_finalize_request() 

680 

681 # Wrap the request business logic in a function to be retried. 

682 def retriable_request(): 

683 result = transport.request( 

684 method, url, data=payload, headers=headers, timeout=timeout 

685 ) 

686 

687 self._process_finalize_response(result) 

688 

689 return result 

690 

691 return _request_helpers.wait_and_retry(retriable_request, self._retry_strategy) 

692 

693 def cancel( 

694 self, 

695 transport, 

696 timeout=( 

697 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

698 _request_helpers._DEFAULT_READ_TIMEOUT, 

699 ), 

700 ): 

701 """Cancel an MPU request and permanently delete any uploaded parts. 

702 

703 This cannot be undone. 

704 

705 Args: 

706 transport (object): An object which can make authenticated 

707 requests. 

708 timeout (Optional[Union[float, Tuple[float, float]]]): 

709 The number of seconds to wait for the server response. 

710 Depending on the retry strategy, a request may be repeated 

711 several times using the same timeout each time. 

712 

713 Can also be passed as a tuple (connect_timeout, read_timeout). 

714 See :meth:`requests.Session.request` documentation for details. 

715 

716 Returns: 

717 ~requests.Response: The HTTP response returned by ``transport``. 

718 """ 

719 method, url, payload, headers = self._prepare_cancel_request() 

720 

721 # Wrap the request business logic in a function to be retried. 

722 def retriable_request(): 

723 result = transport.request( 

724 method, url, data=payload, headers=headers, timeout=timeout 

725 ) 

726 

727 self._process_cancel_response(result) 

728 

729 return result 

730 

731 return _request_helpers.wait_and_retry(retriable_request, self._retry_strategy) 

732 

733 

734class XMLMPUPart(_request_helpers.RequestsMixin, _upload.XMLMPUPart): 

735 def upload( 

736 self, 

737 transport, 

738 timeout=( 

739 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

740 _request_helpers._DEFAULT_READ_TIMEOUT, 

741 ), 

742 ): 

743 """Upload the part. 

744 

745 Args: 

746 transport (object): An object which can make authenticated 

747 requests. 

748 timeout (Optional[Union[float, Tuple[float, float]]]): 

749 The number of seconds to wait for the server response. 

750 Depending on the retry strategy, a request may be repeated 

751 several times using the same timeout each time. 

752 

753 Can also be passed as a tuple (connect_timeout, read_timeout). 

754 See :meth:`requests.Session.request` documentation for details. 

755 

756 Returns: 

757 ~requests.Response: The HTTP response returned by ``transport``. 

758 """ 

759 method, url, payload, headers = self._prepare_upload_request() 

760 

761 # Wrap the request business logic in a function to be retried. 

762 def retriable_request(): 

763 result = transport.request( 

764 method, url, data=payload, headers=headers, timeout=timeout 

765 ) 

766 

767 self._process_upload_response(result) 

768 

769 return result 

770 

771 return _request_helpers.wait_and_retry(retriable_request, self._retry_strategy)