Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/google/resumable_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 

21from google.resumable_media import _upload 

22from google.resumable_media.requests import _request_helpers 

23 

24 

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

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

27 

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

29 in a single request. 

30 

31 Args: 

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

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

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

35 

36 Attributes: 

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

38 """ 

39 

40 def transmit( 

41 self, 

42 transport, 

43 data, 

44 content_type, 

45 timeout=( 

46 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

47 _request_helpers._DEFAULT_READ_TIMEOUT, 

48 ), 

49 ): 

50 """Transmit the resource to be uploaded. 

51 

52 Args: 

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

54 make authenticated requests. 

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

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

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

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

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

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

61 several times using the same timeout each time. 

62 

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

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

65 

66 Returns: 

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

68 """ 

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

70 

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

72 def retriable_request(): 

73 result = transport.request( 

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

75 ) 

76 

77 self._process_response(result) 

78 

79 return result 

80 

81 return _request_helpers.wait_and_retry( 

82 retriable_request, self._get_status_code, self._retry_strategy 

83 ) 

84 

85 

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

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

88 

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

90 (multipart) request. 

91 

92 Args: 

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

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

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

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

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

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

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

100 "crc32c" and None. The default is None. 

101 

102 Attributes: 

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

104 """ 

105 

106 def transmit( 

107 self, 

108 transport, 

109 data, 

110 metadata, 

111 content_type, 

112 timeout=( 

113 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

114 _request_helpers._DEFAULT_READ_TIMEOUT, 

115 ), 

116 ): 

117 """Transmit the resource to be uploaded. 

118 

119 Args: 

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

121 make authenticated requests. 

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

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

124 ACL list. 

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

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

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

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

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

130 several times using the same timeout each time. 

131 

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

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

134 

135 Returns: 

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

137 """ 

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

139 data, metadata, content_type 

140 ) 

141 

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

143 def retriable_request(): 

144 result = transport.request( 

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

146 ) 

147 

148 self._process_response(result) 

149 

150 return result 

151 

152 return _request_helpers.wait_and_retry( 

153 retriable_request, self._get_status_code, self._retry_strategy 

154 ) 

155 

156 

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

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

159 

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

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

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

163 the user) until all bytes have been uploaded. 

164 

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

166 the chunk size are required: 

167 

168 .. testsetup:: resumable-constructor 

169 

170 bucket = 'bucket-foo' 

171 

172 .. doctest:: resumable-constructor 

173 

174 >>> from google.resumable_media.requests import ResumableUpload 

175 >>> 

176 >>> url_template = ( 

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

178 ... 'uploadType=resumable') 

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

180 >>> 

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

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

183 

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

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

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

187 

188 .. testsetup:: resumable-explicit-size 

189 

190 import os 

191 import tempfile 

192 

193 import mock 

194 import requests 

195 import http.client 

196 

197 from google.resumable_media.requests import ResumableUpload 

198 

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

200 chunk_size = 3 * 1024 * 1024 # 3MB 

201 upload = ResumableUpload(upload_url, chunk_size) 

202 

203 file_desc, filename = tempfile.mkstemp() 

204 os.close(file_desc) 

205 

206 data = b'some bytes!' 

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

208 file_obj.write(data) 

209 

210 fake_response = requests.Response() 

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

212 fake_response._content = b'' 

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

214 fake_response.headers['location'] = resumable_url 

215 

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

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

218 

219 .. doctest:: resumable-explicit-size 

220 

221 >>> import os 

222 >>> 

223 >>> upload.total_bytes is None 

224 True 

225 >>> 

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

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

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

229 >>> response = upload.initiate( 

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

231 ... total_bytes=total_bytes) 

232 >>> response 

233 <Response [200]> 

234 >>> 

235 >>> upload.total_bytes == total_bytes 

236 True 

237 

238 .. testcleanup:: resumable-explicit-size 

239 

240 os.remove(filename) 

241 

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

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

244 from the ``stream`` itself: 

245 

246 .. testsetup:: resumable-implicit-size 

247 

248 import io 

249 

250 import mock 

251 import requests 

252 import http.client 

253 

254 from google.resumable_media.requests import ResumableUpload 

255 

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

257 chunk_size = 3 * 1024 * 1024 # 3MB 

258 upload = ResumableUpload(upload_url, chunk_size) 

259 

260 fake_response = requests.Response() 

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

262 fake_response._content = b'' 

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

264 fake_response.headers['location'] = resumable_url 

265 

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

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

268 

269 data = b'some MOAR bytes!' 

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

271 content_type = 'image/jpeg' 

272 

273 .. doctest:: resumable-implicit-size 

274 

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

276 >>> response = upload.initiate( 

277 ... transport, stream, metadata, content_type) 

278 >>> 

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

280 True 

281 

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

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

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

285 logs). To use this argument: 

286 

287 .. testsetup:: resumable-unknown-size 

288 

289 import io 

290 

291 import mock 

292 import requests 

293 import http.client 

294 

295 from google.resumable_media.requests import ResumableUpload 

296 

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

298 chunk_size = 3 * 1024 * 1024 # 3MB 

299 upload = ResumableUpload(upload_url, chunk_size) 

300 

301 fake_response = requests.Response() 

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

303 fake_response._content = b'' 

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

305 fake_response.headers['location'] = resumable_url 

306 

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

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

309 

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

311 content_type = 'application/octet-stream' 

312 

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

314 

315 .. doctest:: resumable-unknown-size 

316 

317 >>> response = upload.initiate( 

318 ... transport, stream, metadata, content_type, 

319 ... stream_final=False) 

320 >>> 

321 >>> upload.total_bytes is None 

322 True 

323 

324 Args: 

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

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

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

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

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

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

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

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

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

334 and google.resumable_media.common.DataCorruption will be raised on 

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

336 host automatically. Supported values are "md5", "crc32c" and None. 

337 The default is None. 

338 

339 Attributes: 

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

341 

342 Raises: 

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

344 :data:`.UPLOAD_CHUNK_SIZE`. 

345 """ 

346 

347 def initiate( 

348 self, 

349 transport, 

350 stream, 

351 metadata, 

352 content_type, 

353 total_bytes=None, 

354 stream_final=True, 

355 timeout=( 

356 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

357 _request_helpers._DEFAULT_READ_TIMEOUT, 

358 ), 

359 ): 

360 """Initiate a resumable upload. 

361 

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

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

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

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

366 is attached to application logs. 

367 

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

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

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

371 size, the upload will be concluded. 

372 

373 Args: 

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

375 make authenticated requests. 

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

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

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

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

380 ACL list. 

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

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

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

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

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

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

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

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

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

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

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

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

393 several times using the same timeout each time. 

394 

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

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

397 

398 Returns: 

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

400 """ 

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

402 stream, 

403 metadata, 

404 content_type, 

405 total_bytes=total_bytes, 

406 stream_final=stream_final, 

407 ) 

408 

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

410 def retriable_request(): 

411 result = transport.request( 

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

413 ) 

414 

415 self._process_initiate_response(result) 

416 

417 return result 

418 

419 return _request_helpers.wait_and_retry( 

420 retriable_request, self._get_status_code, self._retry_strategy 

421 ) 

422 

423 def transmit_next_chunk( 

424 self, 

425 transport, 

426 timeout=( 

427 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

428 _request_helpers._DEFAULT_READ_TIMEOUT, 

429 ), 

430 ): 

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

432 

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

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

435 The upload will be considered complete if the stream produces 

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

437 

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

439 failed response: 

440 

441 .. testsetup:: bad-response 

442 

443 import io 

444 

445 import mock 

446 import requests 

447 import http.client 

448 

449 from google import resumable_media 

450 import google.resumable_media.requests.upload as upload_mod 

451 

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

453 fake_response = requests.Response() 

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

455 transport.request.return_value = fake_response 

456 

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

458 upload = upload_mod.ResumableUpload( 

459 upload_url, resumable_media.UPLOAD_CHUNK_SIZE) 

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

461 data = b'data is here' 

462 upload._stream = io.BytesIO(data) 

463 upload._total_bytes = len(data) 

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

465 

466 .. doctest:: bad-response 

467 :options: +NORMALIZE_WHITESPACE 

468 

469 >>> error = None 

470 >>> try: 

471 ... upload.transmit_next_chunk(transport) 

472 ... except resumable_media.InvalidResponse as caught_exc: 

473 ... error = caught_exc 

474 ... 

475 >>> error 

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

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

478 >>> error.response 

479 <Response [400]> 

480 

481 Args: 

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

483 make authenticated requests. 

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

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

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

487 several times using the same timeout each time. 

488 

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

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

491 

492 Returns: 

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

494 

495 Raises: 

496 ~google.resumable_media.common.InvalidResponse: If the status 

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

498 ~google.resumable_media.common.DataCorruption: If this is the final 

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

500 does not match or is not available. 

501 """ 

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

503 

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

505 def retriable_request(): 

506 result = transport.request( 

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

508 ) 

509 

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

511 

512 return result 

513 

514 return _request_helpers.wait_and_retry( 

515 retriable_request, self._get_status_code, self._retry_strategy 

516 ) 

517 

518 def recover(self, transport): 

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

520 

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

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

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

524 for more information. 

525 

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

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

528 

529 Args: 

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

531 make authenticated requests. 

532 

533 Returns: 

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

535 """ 

536 timeout = ( 

537 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

538 _request_helpers._DEFAULT_READ_TIMEOUT, 

539 ) 

540 

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

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

543 

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

545 def retriable_request(): 

546 result = transport.request( 

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

548 ) 

549 

550 self._process_recover_response(result) 

551 

552 return result 

553 

554 return _request_helpers.wait_and_retry( 

555 retriable_request, self._get_status_code, self._retry_strategy 

556 ) 

557 

558 

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

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

561 

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

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

564 parts can be uploaded concurrently. 

565 

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

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

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

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

570 container automatically. 

571 

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

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

574 throughout. 

575 

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

577 

578 Args: 

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

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

581 varying query parameters. 

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

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

584 encrypted data. These headers will be propagated to individual 

585 XMLMPUPart objects spawned from this container as well. 

586 

587 Attributes: 

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

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

590 response. 

591 """ 

592 

593 def initiate( 

594 self, 

595 transport, 

596 content_type, 

597 timeout=( 

598 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

599 _request_helpers._DEFAULT_READ_TIMEOUT, 

600 ), 

601 ): 

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

603 

604 Args: 

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

606 requests. 

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

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

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

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

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

612 several times using the same timeout each time. 

613 

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

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

616 

617 Returns: 

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

619 """ 

620 

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

622 content_type, 

623 ) 

624 

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

626 def retriable_request(): 

627 result = transport.request( 

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

629 ) 

630 

631 self._process_initiate_response(result) 

632 

633 return result 

634 

635 return _request_helpers.wait_and_retry( 

636 retriable_request, self._get_status_code, self._retry_strategy 

637 ) 

638 

639 def finalize( 

640 self, 

641 transport, 

642 timeout=( 

643 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

644 _request_helpers._DEFAULT_READ_TIMEOUT, 

645 ), 

646 ): 

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

648 

649 Args: 

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

651 requests. 

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

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

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

655 several times using the same timeout each time. 

656 

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

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

659 

660 Returns: 

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

662 """ 

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

664 

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

666 def retriable_request(): 

667 result = transport.request( 

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

669 ) 

670 

671 self._process_finalize_response(result) 

672 

673 return result 

674 

675 return _request_helpers.wait_and_retry( 

676 retriable_request, self._get_status_code, self._retry_strategy 

677 ) 

678 

679 def cancel( 

680 self, 

681 transport, 

682 timeout=( 

683 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

684 _request_helpers._DEFAULT_READ_TIMEOUT, 

685 ), 

686 ): 

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

688 

689 This cannot be undone. 

690 

691 Args: 

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

693 requests. 

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

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

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

697 several times using the same timeout each time. 

698 

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

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

701 

702 Returns: 

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

704 """ 

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

706 

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

708 def retriable_request(): 

709 result = transport.request( 

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

711 ) 

712 

713 self._process_cancel_response(result) 

714 

715 return result 

716 

717 return _request_helpers.wait_and_retry( 

718 retriable_request, self._get_status_code, self._retry_strategy 

719 ) 

720 

721 

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

723 def upload( 

724 self, 

725 transport, 

726 timeout=( 

727 _request_helpers._DEFAULT_CONNECT_TIMEOUT, 

728 _request_helpers._DEFAULT_READ_TIMEOUT, 

729 ), 

730 ): 

731 """Upload the part. 

732 

733 Args: 

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

735 requests. 

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

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

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

739 several times using the same timeout each time. 

740 

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

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

743 

744 Returns: 

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

746 """ 

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

748 

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

750 def retriable_request(): 

751 result = transport.request( 

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

753 ) 

754 

755 self._process_upload_response(result) 

756 

757 return result 

758 

759 return _request_helpers.wait_and_retry( 

760 retriable_request, self._get_status_code, self._retry_strategy 

761 )