From c36b85dafbf3b5f5be6e3126fbf8bf4db14ed37d Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Wed, 16 Oct 2019 19:20:05 -0700 Subject: [PATCH 01/11] Raise on Single Failure --- .../azure/storage/blob/_shared/base_client.py | 9 ++++++++- .../azure/storage/blob/_shared/base_client_async.py | 9 ++++++++- .../azure/storage/blob/aio/container_client_async.py | 9 +++++++++ .../azure-storage-blob/azure/storage/blob/blob_client.py | 1 + .../azure/storage/blob/container_client.py | 9 +++++++++ 5 files changed, 35 insertions(+), 2 deletions(-) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py index 91205c8f3fdb..a63affc72176 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py @@ -189,6 +189,8 @@ def _batch_send( ): """Given a series of request, do a Storage batch call. """ + # Pop it here, so requests doesn't feel bad about additional kwarg + raise_on_any_failure = kwargs.pop("raise_on_any_failure", True) request = self._client._client.post( # pylint: disable=protected-access url='https://{}/?comp=batch'.format(self.primary_hostname), headers={ @@ -212,7 +214,12 @@ def _batch_send( try: if response.status_code not in [202]: raise HttpResponseError(response=response) - return response.parts() + parts = response.parts() + if raise_on_any_failure: + failures = [p for p in parts if p.status_code not in [202]] + if failures: + raise HttpResponseError(message="There is a partial failure in the batch operation.") + return parts except StorageErrorException as error: process_storage_error(error) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py index e76fad464878..511824a87562 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py @@ -98,6 +98,8 @@ async def _batch_send( ): """Given a series of request, do a Storage batch call. """ + # Pop it here, so requests doesn't feel bad about additional kwarg + raise_on_any_failure = kwargs.pop("raise_on_any_failure", True) request = self._client._client.post( # pylint: disable=protected-access url='https://{}/?comp=batch'.format(self.primary_hostname), headers={ @@ -121,6 +123,11 @@ async def _batch_send( try: if response.status_code not in [202]: raise HttpResponseError(response=response) - return response.parts() # Return an AsyncIterator + parts = response.parts() # Return an AsyncIterator + if raise_on_any_failure: + failures = [p for p in parts if p.status_code not in [202]] + if failures: + raise HttpResponseError(message="There is a partial failure in the batch operation.") + return parts except StorageErrorException as error: process_storage_error(error) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py b/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py index 684034ed93ff..4ef367fbc352 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py @@ -830,6 +830,9 @@ async def delete_blobs( # pylint: disable=arguments-differ the value specified. Specify the wildcard character (*) to perform the operation only if the resource does not exist, and fail the operation if it does exist. + :keyword bool raise_on_any_failure: + This is a boolean param which defaults to True. When this is set, an exception + is raised even if there is a single operation failure. :keyword int timeout: The timeout parameter is expressed in seconds. :return: An async iterator of responses, one for each blob in order @@ -888,6 +891,9 @@ async def set_standard_blob_tier_blobs( Required if the blob has an active lease. Value can be a LeaseClient object or the lease ID as a string. :type lease: ~azure.storage.blob.lease.LeaseClient or str + :keyword bool raise_on_any_failure: + This is a boolean param which defaults to True. When this is set, an exception + is raised even if there is a single operation failure. :return: An async iterator of responses, one for each blob in order :rtype: asynciterator[~azure.core.pipeline.transport.AsyncHttpResponse] """ @@ -941,6 +947,9 @@ async def set_premium_page_blob_tier_blobs( Required if the blob has an active lease. Value can be a LeaseClient object or the lease ID as a string. :type lease: ~azure.storage.blob.lease.LeaseClient or str + :keyword bool raise_on_any_failure: + This is a boolean param which defaults to True. When this is set, an exception + is raised even if there is a single operation failure. :return: An async iterator of responses, one for each blob in order :rtype: asynciterator[~azure.core.pipeline.transport.AsyncHttpResponse] """ diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/blob_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/blob_client.py index 958eeb28bdec..7c5266cf44a9 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/blob_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/blob_client.py @@ -723,6 +723,7 @@ def _generic_delete_blob_options(delete_snapshots=False, **kwargs): delete_snapshots = DeleteSnapshotsOptionType(delete_snapshots) options = { 'timeout': kwargs.pop('timeout', None), + 'raise_on_any_failure': kwargs.pop('raise_on_any_failure', True), 'delete_snapshots': delete_snapshots or None, 'lease_access_conditions': access_conditions, 'modified_access_conditions': mod_conditions} diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py index 15e9012f9b7c..642225c151dc 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py @@ -1097,6 +1097,9 @@ def delete_blobs(self, *blobs, **kwargs): the value specified. Specify the wildcard character (*) to perform the operation only if the resource does not exist, and fail the operation if it does exist. + :keyword bool raise_on_any_failure: + This is a boolean param which defaults to True. When this is set, an exception + is raised even if there is a single operation failure. :keyword int timeout: The timeout parameter is expressed in seconds. :return: An iterator of responses, one for each blob in order @@ -1185,6 +1188,9 @@ def set_standard_blob_tier_blobs( Required if the blob has an active lease. Value can be a LeaseClient object or the lease ID as a string. :type lease: ~azure.storage.blob.LeaseClient or str + :keyword bool raise_on_any_failure: + This is a boolean param which defaults to True. When this is set, an exception + is raised even if there is a single operation failure. :return: An iterator of responses, one for each blob in order :rtype: iterator[~azure.core.pipeline.transport.HttpResponse] """ @@ -1239,6 +1245,9 @@ def set_premium_page_blob_tier_blobs( Required if the blob has an active lease. Value can be a LeaseClient object or the lease ID as a string. :type lease: ~azure.storage.blob.LeaseClient or str + :keyword bool raise_on_any_failure: + This is a boolean param which defaults to True. When this is set, an exception + is raised even if there is a single operation failure. :return: An iterator of responses, one for each blob in order :rtype: iterator[~azure.core.pipeline.transport.HttpResponse] """ From 3ce6655d4c3fa349a53593bba34d2a289751dd98 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Fri, 18 Oct 2019 16:22:55 -0700 Subject: [PATCH 02/11] some changes --- .../azure/storage/blob/_shared/base_client.py | 10 +- .../storage/blob/_shared/base_client_async.py | 17 +- .../storage/blob/_shared/response_handlers.py | 17 + .../blob/aio/container_client_async.py | 9 +- ...standard_blob_tier_set_tier_api_batch.yaml | 1333 +++++++++++++++++ .../tests/test_container.py | 68 +- .../tests/test_container_async.py | 58 +- 7 files changed, 1472 insertions(+), 40 deletions(-) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py index a63affc72176..251506140950 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py @@ -48,7 +48,7 @@ ExponentialRetry, ) from .._generated.models import StorageErrorException -from .response_handlers import process_storage_error +from .response_handlers import process_storage_error, PartialBatchErrorException _LOGGER = logging.getLogger(__name__) @@ -216,10 +216,12 @@ def _batch_send( raise HttpResponseError(response=response) parts = response.parts() if raise_on_any_failure: - failures = [p for p in parts if p.status_code not in [202]] + failures = [p for p in parts if p.status_code not in [200, 202]] if failures: - raise HttpResponseError(message="There is a partial failure in the batch operation.") - return parts + error = PartialBatchErrorException(message="There is a partial failure in the batch operation.", response=response, parts=iter(parts)) + error.failed_operations = failures + raise error + return iter(parts) except StorageErrorException as error: process_storage_error(error) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py index 511824a87562..fb5f23d415a6 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py @@ -9,8 +9,8 @@ TYPE_CHECKING ) import logging - from azure.core.pipeline import AsyncPipeline +from azure.core.async_paging import AsyncList from azure.core.exceptions import HttpResponseError from azure.core.pipeline.policies.distributed_tracing import DistributedTracingPolicy from azure.core.pipeline.policies import ( @@ -30,7 +30,7 @@ from .policies_async import AsyncStorageResponseHook from .._generated.models import StorageErrorException -from .response_handlers import process_storage_error +from .response_handlers import process_storage_error, PartialBatchErrorException if TYPE_CHECKING: from azure.core.pipeline import Pipeline @@ -124,10 +124,17 @@ async def _batch_send( if response.status_code not in [202]: raise HttpResponseError(response=response) parts = response.parts() # Return an AsyncIterator + parts_list = [] if raise_on_any_failure: - failures = [p for p in parts if p.status_code not in [202]] + failures = [] + async for part in parts: + parts_list.append(part) + if part.status_code not in [200,202]: + failures.append(part) if failures: - raise HttpResponseError(message="There is a partial failure in the batch operation.") - return parts + error = PartialBatchErrorException(message="There is a partial failure in the batch operation.", response=response, parts=AsyncList(parts_list)) + error.failed_operations = failures + raise error + return AsyncList(parts_list) except StorageErrorException as error: process_storage_error(error) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py index fbf9889d762c..cd768f22ca30 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py @@ -31,6 +31,23 @@ _LOGGER = logging.getLogger(__name__) +class PartialBatchErrorException(HttpResponseError): + """There is a partial failure in batch operations. + + :param deserialize: A deserializer + :param response: Server response to be deserialized. + """ + + def __init__(self, message, response, parts): + + self.response = response + self.parts = parts + self.failed_operations = None + self.message = message + self.response.status_code = 207 + super(PartialBatchErrorException, self).__init__(message=self.message, response=response) + + def parse_length_from_content_range(content_range): ''' Parses the blob length from the content range header: bytes 1-3/65537 diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py b/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py index 4ef367fbc352..7bb83215e7bd 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py @@ -832,7 +832,8 @@ async def delete_blobs( # pylint: disable=arguments-differ operation if it does exist. :keyword bool raise_on_any_failure: This is a boolean param which defaults to True. When this is set, an exception - is raised even if there is a single operation failure. + is raised even if there is a single operation failure. For optimal performance, + this should be set to False :keyword int timeout: The timeout parameter is expressed in seconds. :return: An async iterator of responses, one for each blob in order @@ -893,7 +894,8 @@ async def set_standard_blob_tier_blobs( :type lease: ~azure.storage.blob.lease.LeaseClient or str :keyword bool raise_on_any_failure: This is a boolean param which defaults to True. When this is set, an exception - is raised even if there is a single operation failure. + is raised even if there is a single operation failure. For optimal performance, + this should be set to False. :return: An async iterator of responses, one for each blob in order :rtype: asynciterator[~azure.core.pipeline.transport.AsyncHttpResponse] """ @@ -949,7 +951,8 @@ async def set_premium_page_blob_tier_blobs( :type lease: ~azure.storage.blob.lease.LeaseClient or str :keyword bool raise_on_any_failure: This is a boolean param which defaults to True. When this is set, an exception - is raised even if there is a single operation failure. + is raised even if there is a single operation failure. For optimal performance, + this should be set to False. :return: An async iterator of responses, one for each blob in order :rtype: asynciterator[~azure.core.pipeline.transport.AsyncHttpResponse] """ diff --git a/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_standard_blob_tier_set_tier_api_batch.yaml b/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_standard_blob_tier_set_tier_api_batch.yaml index 3598cbef77e2..a3208b725429 100644 --- a/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_standard_blob_tier_set_tier_api_batch.yaml +++ b/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_standard_blob_tier_set_tier_api_batch.yaml @@ -1319,4 +1319,1337 @@ interactions: status: code: 202 message: Accepted +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 8f52b076-f1e4-11e9-828f-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:17 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containera687174a?restype=container + response: + body: + string: "\uFEFFContainerAlreadyExistsThe + specified container already exists.\nRequestId:ecec2d98-401e-00ac-7bf1-854597000000\nTime:2019-10-18T20:19:16.5496175Z" + headers: + Content-Length: + - '230' + Content-Type: + - application/xml + Date: + - Fri, 18 Oct 2019 20:19:16 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-error-code: + - ContainerAlreadyExists + x-ms-request-id: + - ecec2d98-401e-00ac-7bf1-854597000000 + x-ms-version: + - '2019-02-02' + status: + code: 409 + message: The specified container already exists. +- request: + body: "--===============0874942346==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: + binary\r\nContent-ID: 0\r\n\r\nDELETE /containera687174a/blob1? HTTP/1.1\r\nx-ms-date: + Fri, 18 Oct 2019 20:19:17 GMT\r\nx-ms-client-request-id: 8f98fe14-f1e4-11e9-95c8-2816a845e8c6\r\nAuthorization: + SharedKey blobstoragename:dSiwALXA1UOw/16RwvZrVH+x8ScQ5rvXTEE4mYM8omo=\r\n\r\n\r\n--===============0874942346==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 1\r\n\r\nDELETE + /containera687174a/blob2? HTTP/1.1\r\nx-ms-date: Fri, 18 Oct 2019 20:19:17 GMT\r\nx-ms-client-request-id: + 8f98fe15-f1e4-11e9-819f-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:bgYwTwL8INPYV+f0qUCFGj26JcCFUKWqtCI/OsDrc28=\r\n\r\n\r\n--===============0874942346==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 2\r\n\r\nDELETE + /containera687174a/blob3? HTTP/1.1\r\nx-ms-date: Fri, 18 Oct 2019 20:19:17 GMT\r\nx-ms-client-request-id: + 8f9924e8-f1e4-11e9-b0ba-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:pGHwMN7U+riFvAC36v6dVnMss0zbyPdexrkJcfk/ZK0=\r\n\r\n\r\n--===============0874942346==--\r\n" + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1071' + Content-Type: + - multipart/mixed; boundary================0874942346== + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 8f9c58a8-f1e4-11e9-a96b-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:17 GMT + x-ms-version: + - '2019-02-02' + method: POST + uri: https://blobstoragename.blob.core.windows.net/?comp=batch + response: + body: + string: "--batchresponse_0e520e71-9591-4ec3-a513-20160b9cd3bc\r\nContent-Type: + application/http\r\nContent-ID: 0\r\n\r\nHTTP/1.1 404 The specified blob does + not exist.\r\nx-ms-error-code: BlobNotFound\r\nx-ms-request-id: ecec2db3-401e-00ac-12f1-8545971e82d4\r\nx-ms-version: + 2019-02-02\r\nContent-Length: 216\r\nContent-Type: application/xml\r\nServer: + Windows-Azure-Blob/1.0\r\n\r\n\uFEFF\nBlobNotFoundThe + specified blob does not exist.\nRequestId:ecec2db3-401e-00ac-12f1-8545971e82d4\nTime:2019-10-18T20:19:16.8448259Z\r\n--batchresponse_0e520e71-9591-4ec3-a513-20160b9cd3bc\r\nContent-Type: + application/http\r\nContent-ID: 1\r\n\r\nHTTP/1.1 404 The specified blob does + not exist.\r\nx-ms-error-code: BlobNotFound\r\nx-ms-request-id: ecec2db3-401e-00ac-12f1-8545971e82d8\r\nx-ms-version: + 2019-02-02\r\nContent-Length: 216\r\nContent-Type: application/xml\r\nServer: + Windows-Azure-Blob/1.0\r\n\r\n\uFEFF\nBlobNotFoundThe + specified blob does not exist.\nRequestId:ecec2db3-401e-00ac-12f1-8545971e82d8\nTime:2019-10-18T20:19:16.8478280Z\r\n--batchresponse_0e520e71-9591-4ec3-a513-20160b9cd3bc\r\nContent-Type: + application/http\r\nContent-ID: 2\r\n\r\nHTTP/1.1 404 The specified blob does + not exist.\r\nx-ms-error-code: BlobNotFound\r\nx-ms-request-id: ecec2db3-401e-00ac-12f1-8545971e82d9\r\nx-ms-version: + 2019-02-02\r\nContent-Length: 216\r\nContent-Type: application/xml\r\nServer: + Windows-Azure-Blob/1.0\r\n\r\n\uFEFF\nBlobNotFoundThe + specified blob does not exist.\nRequestId:ecec2db3-401e-00ac-12f1-8545971e82d9\nTime:2019-10-18T20:19:16.8478280Z\r\n--batchresponse_0e520e71-9591-4ec3-a513-20160b9cd3bc--" + headers: + Content-Type: + - multipart/mixed; boundary=batchresponse_0e520e71-9591-4ec3-a513-20160b9cd3bc + Date: + - Fri, 18 Oct 2019 20:19:16 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Transfer-Encoding: + - chunked + x-ms-request-id: + - ecec2db3-401e-00ac-12f1-854597000000 + x-ms-version: + - '2019-02-02' + status: + code: 202 + message: Accepted +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - 8ff5ad28-f1e4-11e9-8b25-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:18 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob1 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Fri, 18 Oct 2019 20:19:17 GMT + ETag: + - '"0x8D7540873A08507"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:17 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - ecec2e4d-401e-00ac-1ef1-854597000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - 900900f6-f1e4-11e9-87d7-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:18 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob2 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Fri, 18 Oct 2019 20:19:17 GMT + ETag: + - '"0x8D7540873B26290"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:17 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - ecec2e6c-401e-00ac-3bf1-854597000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - 90179c70-f1e4-11e9-bab3-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:18 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob3 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Fri, 18 Oct 2019 20:19:17 GMT + ETag: + - '"0x8D7540873C0BD06"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:17 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - ecec2e87-401e-00ac-52f1-854597000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 9024aac8-f1e4-11e9-9bc4-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:18 GMT + x-ms-version: + - '2019-02-02' + method: HEAD + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob1 + response: + body: + string: '' + headers: + Accept-Ranges: + - bytes + Content-Length: + - '11' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Content-Type: + - application/octet-stream + Date: + - Fri, 18 Oct 2019 20:19:17 GMT + ETag: + - '"0x8D7540873A08507"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:17 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Vary: + - Origin + x-ms-access-tier: + - Hot + x-ms-access-tier-inferred: + - 'true' + x-ms-blob-type: + - BlockBlob + x-ms-creation-time: + - Fri, 18 Oct 2019 20:19:17 GMT + x-ms-lease-state: + - available + x-ms-lease-status: + - unlocked + x-ms-request-id: + - ecec2e93-401e-00ac-5ef1-854597000000 + x-ms-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 200 + message: OK +- request: + body: "--===============1052005317==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: + binary\r\nContent-ID: 0\r\n\r\nPUT /containera687174a/blob1?comp=tier HTTP/1.1\r\nContent-Length: + 0\r\nx-ms-access-tier: Archive\r\nx-ms-date: Fri, 18 Oct 2019 20:19:18 GMT\r\nx-ms-client-request-id: + 90317340-f1e4-11e9-a595-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:vq7juZFevGemkGSefkLU4Iz7jmC8HufbyzZ6ox6q3i4=\r\n\r\n\r\n--===============1052005317==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 1\r\n\r\nPUT + /containera687174a/blob2?comp=tier HTTP/1.1\r\nContent-Length: 0\r\nx-ms-access-tier: + Archive\r\nx-ms-date: Fri, 18 Oct 2019 20:19:18 GMT\r\nx-ms-client-request-id: + 90319a36-f1e4-11e9-ad1f-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:VkcxD8DN4JnrtPzHNlZqPolx8pqVkAr1EDHTT5cl0u0=\r\n\r\n\r\n--===============1052005317==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 2\r\n\r\nPUT + /containera687174a/blob3?comp=tier HTTP/1.1\r\nContent-Length: 0\r\nx-ms-access-tier: + Archive\r\nx-ms-date: Fri, 18 Oct 2019 20:19:18 GMT\r\nx-ms-client-request-id: + 90319a37-f1e4-11e9-afe5-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:hr/kuWH0BwXSaOhPZz8RTvMAqw74Os4mfbjju0luUic=\r\n\r\n\r\n--===============1052005317==--\r\n" + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1227' + Content-Type: + - multipart/mixed; boundary================1052005317== + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 9032360c-f1e4-11e9-a052-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:18 GMT + x-ms-version: + - '2019-02-02' + method: POST + uri: https://blobstoragename.blob.core.windows.net/?comp=batch + response: + body: + string: "--batchresponse_23de09c3-8f30-4dbd-9229-d2da1cfadd42\r\nContent-Type: + application/http\r\nContent-ID: 0\r\n\r\nHTTP/1.1 200 OK\r\nx-ms-request-id: + ecec2ea0-401e-00ac-69f1-8545971e82e6\r\nx-ms-version: 2019-02-02\r\nServer: + Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_23de09c3-8f30-4dbd-9229-d2da1cfadd42\r\nContent-Type: + application/http\r\nContent-ID: 1\r\n\r\nHTTP/1.1 200 OK\r\nx-ms-request-id: + ecec2ea0-401e-00ac-69f1-8545971e82e7\r\nx-ms-version: 2019-02-02\r\nServer: + Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_23de09c3-8f30-4dbd-9229-d2da1cfadd42\r\nContent-Type: + application/http\r\nContent-ID: 2\r\n\r\nHTTP/1.1 200 OK\r\nx-ms-request-id: + ecec2ea0-401e-00ac-69f1-8545971e82e8\r\nx-ms-version: 2019-02-02\r\nServer: + Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_23de09c3-8f30-4dbd-9229-d2da1cfadd42--" + headers: + Content-Type: + - multipart/mixed; boundary=batchresponse_23de09c3-8f30-4dbd-9229-d2da1cfadd42 + Date: + - Fri, 18 Oct 2019 20:19:17 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Transfer-Encoding: + - chunked + x-ms-request-id: + - ecec2ea0-401e-00ac-69f1-854597000000 + x-ms-version: + - '2019-02-02' + status: + code: 202 + message: Accepted +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 90486e48-f1e4-11e9-b953-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:18 GMT + x-ms-version: + - '2019-02-02' + method: HEAD + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob1 + response: + body: + string: '' + headers: + Accept-Ranges: + - bytes + Content-Length: + - '11' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Content-Type: + - application/octet-stream + Date: + - Fri, 18 Oct 2019 20:19:17 GMT + ETag: + - '"0x8D7540873A08507"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:17 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Vary: + - Origin + x-ms-access-tier: + - Archive + x-ms-access-tier-change-time: + - Fri, 18 Oct 2019 20:19:17 GMT + x-ms-blob-type: + - BlockBlob + x-ms-creation-time: + - Fri, 18 Oct 2019 20:19:17 GMT + x-ms-lease-state: + - available + x-ms-lease-status: + - unlocked + x-ms-request-id: + - ecec2eba-401e-00ac-03f1-854597000000 + x-ms-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 200 + message: OK +- request: + body: "--===============1086790154==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: + binary\r\nContent-ID: 0\r\n\r\nDELETE /containera687174a/blob1? HTTP/1.1\r\nx-ms-date: + Fri, 18 Oct 2019 20:19:18 GMT\r\nx-ms-client-request-id: 905b4cb8-f1e4-11e9-9bb0-2816a845e8c6\r\nAuthorization: + SharedKey blobstoragename:mt2cG+LKvp0+SzJc6jTyuhingpZNZ25plOsgqh9lDuM=\r\n\r\n\r\n--===============1086790154==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 1\r\n\r\nDELETE + /containera687174a/blob2? HTTP/1.1\r\nx-ms-date: Fri, 18 Oct 2019 20:19:18 GMT\r\nx-ms-client-request-id: + 905b4cb9-f1e4-11e9-8c3b-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:uyp9JyMQj9LKzqxPTRcpaEfSZex8uj+xYOaMimZzHtQ=\r\n\r\n\r\n--===============1086790154==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 2\r\n\r\nDELETE + /containera687174a/blob3? HTTP/1.1\r\nx-ms-date: Fri, 18 Oct 2019 20:19:18 GMT\r\nx-ms-client-request-id: + 905b73b4-f1e4-11e9-a5db-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:u60E25Iavq2SrvtTCkaxh2tpzFcU6MMJzi9jX2EnuZY=\r\n\r\n\r\n--===============1086790154==--\r\n" + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1071' + Content-Type: + - multipart/mixed; boundary================1086790154== + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 905bc2ba-f1e4-11e9-a0c4-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:18 GMT + x-ms-version: + - '2019-02-02' + method: POST + uri: https://blobstoragename.blob.core.windows.net/?comp=batch + response: + body: + string: "--batchresponse_63f785fb-e738-4873-84ba-bc205f3b889a\r\nContent-Type: + application/http\r\nContent-ID: 0\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-type-permanent: + true\r\nx-ms-request-id: ecec2ecb-401e-00ac-14f1-8545971e82ea\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_63f785fb-e738-4873-84ba-bc205f3b889a\r\nContent-Type: + application/http\r\nContent-ID: 1\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-type-permanent: + true\r\nx-ms-request-id: ecec2ecb-401e-00ac-14f1-8545971e82eb\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_63f785fb-e738-4873-84ba-bc205f3b889a\r\nContent-Type: + application/http\r\nContent-ID: 2\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-type-permanent: + true\r\nx-ms-request-id: ecec2ecb-401e-00ac-14f1-8545971e82ec\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_63f785fb-e738-4873-84ba-bc205f3b889a--" + headers: + Content-Type: + - multipart/mixed; boundary=batchresponse_63f785fb-e738-4873-84ba-bc205f3b889a + Date: + - Fri, 18 Oct 2019 20:19:17 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Transfer-Encoding: + - chunked + x-ms-request-id: + - ecec2ecb-401e-00ac-14f1-854597000000 + x-ms-version: + - '2019-02-02' + status: + code: 202 + message: Accepted +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - 906a85b6-f1e4-11e9-9b5c-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:18 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob1 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Fri, 18 Oct 2019 20:19:17 GMT + ETag: + - '"0x8D7540874157C02"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:18 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - ecec2edc-401e-00ac-22f1-854597000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - 907af5ac-f1e4-11e9-a783-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:19 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob2 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Fri, 18 Oct 2019 20:19:17 GMT + ETag: + - '"0x8D7540874255D5B"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:18 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - ecec2f01-401e-00ac-42f1-854597000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - 908aa274-f1e4-11e9-952d-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:19 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob3 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Fri, 18 Oct 2019 20:19:17 GMT + ETag: + - '"0x8D754087434A260"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:18 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - ecec2f22-401e-00ac-5bf1-854597000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 9099179e-f1e4-11e9-9d73-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:19 GMT + x-ms-version: + - '2019-02-02' + method: HEAD + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob1 + response: + body: + string: '' + headers: + Accept-Ranges: + - bytes + Content-Length: + - '11' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Content-Type: + - application/octet-stream + Date: + - Fri, 18 Oct 2019 20:19:18 GMT + ETag: + - '"0x8D7540874157C02"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:18 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Vary: + - Origin + x-ms-access-tier: + - Hot + x-ms-access-tier-inferred: + - 'true' + x-ms-blob-type: + - BlockBlob + x-ms-creation-time: + - Fri, 18 Oct 2019 20:19:18 GMT + x-ms-lease-state: + - available + x-ms-lease-status: + - unlocked + x-ms-request-id: + - ecec2f3c-401e-00ac-75f1-854597000000 + x-ms-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 200 + message: OK +- request: + body: "--===============0999079139==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: + binary\r\nContent-ID: 0\r\n\r\nPUT /containera687174a/blob1?comp=tier HTTP/1.1\r\nContent-Length: + 0\r\nx-ms-access-tier: Cool\r\nx-ms-date: Fri, 18 Oct 2019 20:19:19 GMT\r\nx-ms-client-request-id: + 90ac919c-f1e4-11e9-8ffc-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:r5bl9p+rGMNvmpFGBFJKllNOM7sKDgYCXVy4TTdmTfY=\r\n\r\n\r\n--===============0999079139==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 1\r\n\r\nPUT + /containera687174a/blob2?comp=tier HTTP/1.1\r\nContent-Length: 0\r\nx-ms-access-tier: + Cool\r\nx-ms-date: Fri, 18 Oct 2019 20:19:19 GMT\r\nx-ms-client-request-id: + 90ac919d-f1e4-11e9-bdf7-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:yQaYYKT/5U9OCtXGmbklNapMyw49cY8SLyz3RTxg0Eo=\r\n\r\n\r\n--===============0999079139==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 2\r\n\r\nPUT + /containera687174a/blob3?comp=tier HTTP/1.1\r\nContent-Length: 0\r\nx-ms-access-tier: + Cool\r\nx-ms-date: Fri, 18 Oct 2019 20:19:19 GMT\r\nx-ms-client-request-id: + 90acb778-f1e4-11e9-be87-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:/gwDYaV4RoefCNZSJCzhUK+buVQoq4P89CeaPBQG/Tc=\r\n\r\n\r\n--===============0999079139==--\r\n" + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1218' + Content-Type: + - multipart/mixed; boundary================0999079139== + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 90ad534c-f1e4-11e9-999d-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:19 GMT + x-ms-version: + - '2019-02-02' + method: POST + uri: https://blobstoragename.blob.core.windows.net/?comp=batch + response: + body: + string: "--batchresponse_f6f2b6a1-841f-43ea-8c8a-1b9f4c40323b\r\nContent-Type: + application/http\r\nContent-ID: 0\r\n\r\nHTTP/1.1 200 OK\r\nx-ms-request-id: + ecec2f54-401e-00ac-0df1-8545971e82f8\r\nx-ms-version: 2019-02-02\r\nServer: + Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_f6f2b6a1-841f-43ea-8c8a-1b9f4c40323b\r\nContent-Type: + application/http\r\nContent-ID: 1\r\n\r\nHTTP/1.1 200 OK\r\nx-ms-request-id: + ecec2f54-401e-00ac-0df1-8545971e82f9\r\nx-ms-version: 2019-02-02\r\nServer: + Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_f6f2b6a1-841f-43ea-8c8a-1b9f4c40323b\r\nContent-Type: + application/http\r\nContent-ID: 2\r\n\r\nHTTP/1.1 200 OK\r\nx-ms-request-id: + ecec2f54-401e-00ac-0df1-8545971e82fa\r\nx-ms-version: 2019-02-02\r\nServer: + Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_f6f2b6a1-841f-43ea-8c8a-1b9f4c40323b--" + headers: + Content-Type: + - multipart/mixed; boundary=batchresponse_f6f2b6a1-841f-43ea-8c8a-1b9f4c40323b + Date: + - Fri, 18 Oct 2019 20:19:18 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Transfer-Encoding: + - chunked + x-ms-request-id: + - ecec2f54-401e-00ac-0df1-854597000000 + x-ms-version: + - '2019-02-02' + status: + code: 202 + message: Accepted +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 90bb5368-f1e4-11e9-8357-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:19 GMT + x-ms-version: + - '2019-02-02' + method: HEAD + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob1 + response: + body: + string: '' + headers: + Accept-Ranges: + - bytes + Content-Length: + - '11' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Content-Type: + - application/octet-stream + Date: + - Fri, 18 Oct 2019 20:19:18 GMT + ETag: + - '"0x8D7540874157C02"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:18 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Vary: + - Origin + x-ms-access-tier: + - Cool + x-ms-access-tier-change-time: + - Fri, 18 Oct 2019 20:19:18 GMT + x-ms-blob-type: + - BlockBlob + x-ms-creation-time: + - Fri, 18 Oct 2019 20:19:18 GMT + x-ms-lease-state: + - available + x-ms-lease-status: + - unlocked + x-ms-request-id: + - ecec2f72-401e-00ac-2bf1-854597000000 + x-ms-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 200 + message: OK +- request: + body: "--===============1854079213==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: + binary\r\nContent-ID: 0\r\n\r\nDELETE /containera687174a/blob1? HTTP/1.1\r\nx-ms-date: + Fri, 18 Oct 2019 20:19:19 GMT\r\nx-ms-client-request-id: 90c8b898-f1e4-11e9-8fcc-2816a845e8c6\r\nAuthorization: + SharedKey blobstoragename:RR3XJa2KBJs7mDxcxA5RjVRYmNc4PRhaMfLqhCD+WkE=\r\n\r\n\r\n--===============1854079213==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 1\r\n\r\nDELETE + /containera687174a/blob2? HTTP/1.1\r\nx-ms-date: Fri, 18 Oct 2019 20:19:19 GMT\r\nx-ms-client-request-id: + 90c8dfdc-f1e4-11e9-b0b3-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:58DuGCd5X8NiiclgOfCtW3SnnZGCXnjGJ6hmMPbqdgY=\r\n\r\n\r\n--===============1854079213==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 2\r\n\r\nDELETE + /containera687174a/blob3? HTTP/1.1\r\nx-ms-date: Fri, 18 Oct 2019 20:19:19 GMT\r\nx-ms-client-request-id: + 90c8dfdd-f1e4-11e9-b12f-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:JbeAwprDYtsDzTIJjqi+zT5M9ErImhPHUmYrI9FLTUU=\r\n\r\n\r\n--===============1854079213==--\r\n" + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1071' + Content-Type: + - multipart/mixed; boundary================1854079213== + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 90c95458-f1e4-11e9-89ea-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:19 GMT + x-ms-version: + - '2019-02-02' + method: POST + uri: https://blobstoragename.blob.core.windows.net/?comp=batch + response: + body: + string: "--batchresponse_f0e0730a-94eb-4ec3-b0ea-6b6f76cdf756\r\nContent-Type: + application/http\r\nContent-ID: 0\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-type-permanent: + true\r\nx-ms-request-id: ecec2f84-401e-00ac-3df1-8545971e82fd\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_f0e0730a-94eb-4ec3-b0ea-6b6f76cdf756\r\nContent-Type: + application/http\r\nContent-ID: 1\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-type-permanent: + true\r\nx-ms-request-id: ecec2f84-401e-00ac-3df1-8545971e82fe\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_f0e0730a-94eb-4ec3-b0ea-6b6f76cdf756\r\nContent-Type: + application/http\r\nContent-ID: 2\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-type-permanent: + true\r\nx-ms-request-id: ecec2f84-401e-00ac-3df1-8545971e82ff\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_f0e0730a-94eb-4ec3-b0ea-6b6f76cdf756--" + headers: + Content-Type: + - multipart/mixed; boundary=batchresponse_f0e0730a-94eb-4ec3-b0ea-6b6f76cdf756 + Date: + - Fri, 18 Oct 2019 20:19:18 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Transfer-Encoding: + - chunked + x-ms-request-id: + - ecec2f84-401e-00ac-3df1-854597000000 + x-ms-version: + - '2019-02-02' + status: + code: 202 + message: Accepted +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - 90d7efac-f1e4-11e9-b8ba-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:19 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob1 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Fri, 18 Oct 2019 20:19:18 GMT + ETag: + - '"0x8D754087484575B"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:18 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - ecec2fa1-401e-00ac-54f1-854597000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - 90e997fa-f1e4-11e9-b2aa-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:19 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob2 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Fri, 18 Oct 2019 20:19:18 GMT + ETag: + - '"0x8D7540874968315"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:18 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - ecec2fbe-401e-00ac-6cf1-854597000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - 90fe4aa4-f1e4-11e9-941c-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:19 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob3 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Fri, 18 Oct 2019 20:19:18 GMT + ETag: + - '"0x8D7540874AAF922"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:19 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - ecec2fda-401e-00ac-05f1-854597000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 910f5646-f1e4-11e9-8d05-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:20 GMT + x-ms-version: + - '2019-02-02' + method: HEAD + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob1 + response: + body: + string: '' + headers: + Accept-Ranges: + - bytes + Content-Length: + - '11' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Content-Type: + - application/octet-stream + Date: + - Fri, 18 Oct 2019 20:19:18 GMT + ETag: + - '"0x8D754087484575B"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:18 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Vary: + - Origin + x-ms-access-tier: + - Hot + x-ms-access-tier-inferred: + - 'true' + x-ms-blob-type: + - BlockBlob + x-ms-creation-time: + - Fri, 18 Oct 2019 20:19:18 GMT + x-ms-lease-state: + - available + x-ms-lease-status: + - unlocked + x-ms-request-id: + - ecec2ffd-401e-00ac-24f1-854597000000 + x-ms-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 200 + message: OK +- request: + body: "--===============0629394972==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: + binary\r\nContent-ID: 0\r\n\r\nPUT /containera687174a/blob1?comp=tier HTTP/1.1\r\nContent-Length: + 0\r\nx-ms-access-tier: Hot\r\nx-ms-date: Fri, 18 Oct 2019 20:19:20 GMT\r\nx-ms-client-request-id: + 91212450-f1e4-11e9-9956-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:acpxFhstBPaaYVbm5ePsCpnJuNlLQy8VfHmQHPlws6o=\r\n\r\n\r\n--===============0629394972==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 1\r\n\r\nPUT + /containera687174a/blob2?comp=tier HTTP/1.1\r\nContent-Length: 0\r\nx-ms-access-tier: + Hot\r\nx-ms-date: Fri, 18 Oct 2019 20:19:20 GMT\r\nx-ms-client-request-id: 9121498a-f1e4-11e9-ba54-2816a845e8c6\r\nAuthorization: + SharedKey blobstoragename:gpo+rcVAcYooQ8aAOIhNUkZBE4E1Z/e0XdnbMAHqgtg=\r\n\r\n\r\n--===============0629394972==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 2\r\n\r\nPUT + /containera687174a/blob3?comp=tier HTTP/1.1\r\nContent-Length: 0\r\nx-ms-access-tier: + Hot\r\nx-ms-date: Fri, 18 Oct 2019 20:19:20 GMT\r\nx-ms-client-request-id: 91219782-f1e4-11e9-a135-2816a845e8c6\r\nAuthorization: + SharedKey blobstoragename:POirm154RbAd7rbIPdsKeUoOOOBTsJMZaGNg6cqnp+g=\r\n\r\n\r\n--===============0629394972==--\r\n" + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1215' + Content-Type: + - multipart/mixed; boundary================0629394972== + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 9122a99c-f1e4-11e9-a4f7-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:20 GMT + x-ms-version: + - '2019-02-02' + method: POST + uri: https://blobstoragename.blob.core.windows.net/?comp=batch + response: + body: + string: "--batchresponse_72dd1985-388e-4759-a363-4b065df27ab4\r\nContent-Type: + application/http\r\nContent-ID: 0\r\n\r\nHTTP/1.1 200 OK\r\nx-ms-request-id: + ecec3019-401e-00ac-3cf1-8545971e830d\r\nx-ms-version: 2019-02-02\r\nServer: + Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_72dd1985-388e-4759-a363-4b065df27ab4\r\nContent-Type: + application/http\r\nContent-ID: 1\r\n\r\nHTTP/1.1 200 OK\r\nx-ms-request-id: + ecec3019-401e-00ac-3cf1-8545971e830e\r\nx-ms-version: 2019-02-02\r\nServer: + Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_72dd1985-388e-4759-a363-4b065df27ab4\r\nContent-Type: + application/http\r\nContent-ID: 2\r\n\r\nHTTP/1.1 200 OK\r\nx-ms-request-id: + ecec3019-401e-00ac-3cf1-8545971e830f\r\nx-ms-version: 2019-02-02\r\nServer: + Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_72dd1985-388e-4759-a363-4b065df27ab4--" + headers: + Content-Type: + - multipart/mixed; boundary=batchresponse_72dd1985-388e-4759-a363-4b065df27ab4 + Date: + - Fri, 18 Oct 2019 20:19:19 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Transfer-Encoding: + - chunked + x-ms-request-id: + - ecec3019-401e-00ac-3cf1-854597000000 + x-ms-version: + - '2019-02-02' + status: + code: 202 + message: Accepted +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 913670a2-f1e4-11e9-a56c-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:20 GMT + x-ms-version: + - '2019-02-02' + method: HEAD + uri: https://blobstoragename.blob.core.windows.net/containera687174a/blob1 + response: + body: + string: '' + headers: + Accept-Ranges: + - bytes + Content-Length: + - '11' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Content-Type: + - application/octet-stream + Date: + - Fri, 18 Oct 2019 20:19:19 GMT + ETag: + - '"0x8D754087484575B"' + Last-Modified: + - Fri, 18 Oct 2019 20:19:18 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Vary: + - Origin + x-ms-access-tier: + - Hot + x-ms-access-tier-change-time: + - Fri, 18 Oct 2019 20:19:19 GMT + x-ms-blob-type: + - BlockBlob + x-ms-creation-time: + - Fri, 18 Oct 2019 20:19:18 GMT + x-ms-lease-state: + - available + x-ms-lease-status: + - unlocked + x-ms-request-id: + - ecec302f-401e-00ac-50f1-854597000000 + x-ms-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 200 + message: OK +- request: + body: "--===============1661563175==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: + binary\r\nContent-ID: 0\r\n\r\nDELETE /containera687174a/blob1? HTTP/1.1\r\nx-ms-date: + Fri, 18 Oct 2019 20:19:20 GMT\r\nx-ms-client-request-id: 9145a88c-f1e4-11e9-a308-2816a845e8c6\r\nAuthorization: + SharedKey blobstoragename:0wbL5V8uKrEl8X3RfNqNB5WsKkkjclOZYM95YgLTjNs=\r\n\r\n\r\n--===============1661563175==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 1\r\n\r\nDELETE + /containera687174a/blob2? HTTP/1.1\r\nx-ms-date: Fri, 18 Oct 2019 20:19:20 GMT\r\nx-ms-client-request-id: + 9145a88d-f1e4-11e9-907e-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:5FdJIo19saLwW61FaClyjDeu5THyAMA9TtjSXnRkB8g=\r\n\r\n\r\n--===============1661563175==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 2\r\n\r\nDELETE + /containera687174a/blob3? HTTP/1.1\r\nx-ms-date: Fri, 18 Oct 2019 20:19:20 GMT\r\nx-ms-client-request-id: + 9145cf6c-f1e4-11e9-9b09-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:yiZbducz0Yc8NQ5jj6wHHZA68BbCKDuKplTtmqILK8E=\r\n\r\n\r\n--===============1661563175==--\r\n" + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1071' + Content-Type: + - multipart/mixed; boundary================1661563175== + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 9146445a-f1e4-11e9-9b59-2816a845e8c6 + x-ms-date: + - Fri, 18 Oct 2019 20:19:20 GMT + x-ms-version: + - '2019-02-02' + method: POST + uri: https://blobstoragename.blob.core.windows.net/?comp=batch + response: + body: + string: "--batchresponse_661338ce-5585-4f50-9aae-72a108ff5809\r\nContent-Type: + application/http\r\nContent-ID: 0\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-type-permanent: + true\r\nx-ms-request-id: ecec3042-401e-00ac-62f1-8545971e8311\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_661338ce-5585-4f50-9aae-72a108ff5809\r\nContent-Type: + application/http\r\nContent-ID: 1\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-type-permanent: + true\r\nx-ms-request-id: ecec3042-401e-00ac-62f1-8545971e8312\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_661338ce-5585-4f50-9aae-72a108ff5809\r\nContent-Type: + application/http\r\nContent-ID: 2\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-type-permanent: + true\r\nx-ms-request-id: ecec3042-401e-00ac-62f1-8545971e8313\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_661338ce-5585-4f50-9aae-72a108ff5809--" + headers: + Content-Type: + - multipart/mixed; boundary=batchresponse_661338ce-5585-4f50-9aae-72a108ff5809 + Date: + - Fri, 18 Oct 2019 20:19:19 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Transfer-Encoding: + - chunked + x-ms-request-id: + - ecec3042-401e-00ac-62f1-854597000000 + x-ms-version: + - '2019-02-02' + status: + code: 202 + message: Accepted version: 1 diff --git a/sdk/storage/azure-storage-blob/tests/test_container.py b/sdk/storage/azure-storage-blob/tests/test_container.py index 3bd206d347a6..b36ab0f70f39 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container.py +++ b/sdk/storage/azure-storage-blob/tests/test_container.py @@ -1000,6 +1000,7 @@ def test_delete_blobs_simple(self): 'blob2', 'blob3', ) + response = list(response) assert len(response) == 3 assert response[0].status_code == 202 assert response[1].status_code == 202 @@ -1007,36 +1008,66 @@ def test_delete_blobs_simple(self): @pytest.mark.skipif(sys.version_info < (3, 0), reason="Batch not supported on Python 2.7") @record - def test_delete_blobs_snapshot(self): + def test_delete_blobs_simple_no_raise(self): # Arrange container = self._create_container() data = b'hello world' try: - blob1_client = container.get_blob_client('blob1') - blob1_client.upload_blob(data) - blob1_client.create_snapshot() + container.get_blob_client('blob1').upload_blob(data) container.get_blob_client('blob2').upload_blob(data) container.get_blob_client('blob3').upload_blob(data) except: pass - blobs = list(container.list_blobs(include='snapshots')) - assert len(blobs) == 4 # 3 blobs + 1 snapshot # Act response = container.delete_blobs( 'blob1', 'blob2', 'blob3', - delete_snapshots='only' + raise_on_any_failure=False ) + response = list(response) assert len(response) == 3 assert response[0].status_code == 202 - assert response[1].status_code == 404 # There was no snapshot - assert response[2].status_code == 404 # There was no snapshot + assert response[1].status_code == 202 + assert response[2].status_code == 202 + @pytest.mark.skipif(sys.version_info < (3, 0), reason="Batch not supported on Python 2.7") + @record + def test_delete_blobs_snapshot(self): + # Arrange + container = self._create_container() + data = b'hello world' + + try: + blob1_client = container.get_blob_client('blob1') + blob1_client.upload_blob(data) + blob1_client.create_snapshot() + container.get_blob_client('blob2').upload_blob(data) + container.get_blob_client('blob3').upload_blob(data) + except: + pass blobs = list(container.list_blobs(include='snapshots')) - assert len(blobs) == 3 # 3 blobs + assert len(blobs) == 4 # 3 blobs + 1 snapshot + + # Act + try: + response = container.delete_blobs( + 'blob1', + 'blob2', + 'blob3', + delete_snapshots='only' + ) + except HttpResponseError as err: + parts = list(err.parts) + assert len(parts) == 3 + assert parts[0].status_code == 202 + assert parts[1].status_code == 404 # There was no snapshot + assert parts[2].status_code == 404 # There was no snapshot + + blobs = list(container.list_blobs(include='snapshots')) + assert len(blobs) == 3 # 3 blobs @pytest.mark.skipif(sys.version_info < (3, 0), reason="Batch not supported on Python 2.7") @record @@ -1044,13 +1075,15 @@ def test_standard_blob_tier_set_tier_api_batch(self): container = self._create_container() tiers = [StandardBlobTier.Archive, StandardBlobTier.Cool, StandardBlobTier.Hot] - response = container.delete_blobs( - 'blob1', - 'blob2', - 'blob3', - ) - for tier in tiers: + try: + response = container.delete_blobs( + 'blob1', + 'blob2', + 'blob3', + ) + except HttpResponseError as err: + response = err.parts blob = container.get_blob_client('blob1') data = b'hello world' blob.upload_blob(data) @@ -1081,11 +1114,14 @@ def test_standard_blob_tier_set_tier_api_batch(self): assert not blob_ref2.blob_tier_inferred assert blob_ref2.blob_tier_change_time is not None + try: response = container.delete_blobs( 'blob1', 'blob2', 'blob3', ) + except: + pass @pytest.mark.skip(reason="Wasn't able to get premium account with batch enabled") # once we have premium tests, still we don't want to test Py 2.7 diff --git a/sdk/storage/azure-storage-blob/tests/test_container_async.py b/sdk/storage/azure-storage-blob/tests/test_container_async.py index 29487d7141e7..84e7fadea3c0 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_container_async.py @@ -1249,40 +1249,74 @@ async def _test_delete_blobs_simple(self): assert response[2].status_code == 202 @record - def test_delete_blobs_snapshot(self): + def test_delete_blobs_simple_no_raise(self): loop = asyncio.get_event_loop() - loop.run_until_complete(self._test_delete_blobs_snapshot()) + loop.run_until_complete(self._test_delete_blobs_simple()) - async def _test_delete_blobs_snapshot(self): + async def _test_delete_blobs_simple_no_raise(self): # Arrange container = await self._create_container() data = b'hello world' try: - blob1_client = container.get_blob_client('blob1') - await blob1_client.upload_blob(data) - await blob1_client.create_snapshot() + await container.get_blob_client('blob1').upload_blob(data) await container.get_blob_client('blob2').upload_blob(data) await container.get_blob_client('blob3').upload_blob(data) except: pass - blobs = await _to_list(container.list_blobs(include='snapshots')) - assert len(blobs) == 4 # 3 blobs + 1 snapshot # Act response = await _to_list(await container.delete_blobs( 'blob1', 'blob2', 'blob3', - delete_snapshots='only' + raise_on_any_failure=False )) assert len(response) == 3 assert response[0].status_code == 202 - assert response[1].status_code == 404 # There was no snapshot - assert response[2].status_code == 404 # There was no snapshot + assert response[1].status_code == 202 + assert response[2].status_code == 202 + + @record + def test_delete_blobs_snapshot(self): + loop = asyncio.get_event_loop() + loop.run_until_complete(self._test_delete_blobs_snapshot()) + + async def _test_delete_blobs_snapshot(self): + # Arrange + container = await self._create_container() + data = b'hello world' + try: + blob1_client = container.get_blob_client('blob1') + await blob1_client.upload_blob(data) + await blob1_client.create_snapshot() + await container.get_blob_client('blob2').upload_blob(data) + await container.get_blob_client('blob3').upload_blob(data) + except: + pass blobs = await _to_list(container.list_blobs(include='snapshots')) - assert len(blobs) == 3 # 3 blobs + assert len(blobs) == 4 # 3 blobs + 1 snapshot + + # Act + try: + response = await _to_list(await container.delete_blobs( + 'blob1', + 'blob2', + 'blob3', + delete_snapshots='only' + )) + except HttpResponseError as err: + parts_list = [] + async for p in err.parts: + parts_list.append(p) + assert len(parts_list) == 3 + assert parts_list[0].status_code == 202 + assert parts_list[1].status_code == 404 # There was no snapshot + assert parts_list[2].status_code == 404 # There was no snapshot + + blobs = await _to_list(container.list_blobs(include='snapshots')) + assert len(blobs) == 3 # 3 blobs @record def test_standard_blob_tier_set_tier_api_batch(self): From 40394894b242741470e351a7864a5bb8defb9e06 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Fri, 18 Oct 2019 16:35:29 -0700 Subject: [PATCH 03/11] lint --- .../azure/storage/blob/_shared/base_client.py | 5 ++++- .../azure/storage/blob/_shared/base_client_async.py | 7 +++++-- .../azure/storage/blob/_shared/response_handlers.py | 11 +++++------ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py index 251506140950..443aa4114a6c 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py @@ -218,7 +218,10 @@ def _batch_send( if raise_on_any_failure: failures = [p for p in parts if p.status_code not in [200, 202]] if failures: - error = PartialBatchErrorException(message="There is a partial failure in the batch operation.", response=response, parts=iter(parts)) + error = PartialBatchErrorException( + message="There is a partial failure in the batch operation.", + response=response, parts=iter(parts) + ) error.failed_operations = failures raise error return iter(parts) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py index fb5f23d415a6..24a7c00ac773 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py @@ -129,10 +129,13 @@ async def _batch_send( failures = [] async for part in parts: parts_list.append(part) - if part.status_code not in [200,202]: + if part.status_code not in [200, 202]: failures.append(part) if failures: - error = PartialBatchErrorException(message="There is a partial failure in the batch operation.", response=response, parts=AsyncList(parts_list)) + error = PartialBatchErrorException( + message="There is a partial failure in the batch operation.", + response=response, parts=AsyncList(parts_list) + ) error.failed_operations = failures raise error return AsyncList(parts_list) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py index cd768f22ca30..4332e9183dc5 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py @@ -40,12 +40,11 @@ class PartialBatchErrorException(HttpResponseError): def __init__(self, message, response, parts): - self.response = response - self.parts = parts - self.failed_operations = None - self.message = message - self.response.status_code = 207 - super(PartialBatchErrorException, self).__init__(message=self.message, response=response) + self.response = response + self.parts = parts + self.failed_operations = None + self.message = message + super(PartialBatchErrorException, self).__init__(message=self.message, response=response) def parse_length_from_content_range(content_range): From 556fdaeb9e1a5c9caf8f768df7b6bdb872298d95 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Fri, 18 Oct 2019 17:49:18 -0700 Subject: [PATCH 04/11] some changes --- .../azure/storage/blob/_shared/base_client.py | 3 +-- .../azure/storage/blob/_shared/base_client_async.py | 3 +-- .../azure/storage/blob/aio/container_client_async.py | 1 + .../azure-storage-blob/azure/storage/blob/blob_client.py | 1 - .../azure-storage-blob/azure/storage/blob/container_client.py | 1 + sdk/storage/azure-storage-blob/tests/test_container.py | 3 ++- sdk/storage/azure-storage-blob/tests/test_container_async.py | 2 ++ 7 files changed, 8 insertions(+), 6 deletions(-) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py index 443aa4114a6c..c53813d6323d 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py @@ -216,13 +216,12 @@ def _batch_send( raise HttpResponseError(response=response) parts = response.parts() if raise_on_any_failure: - failures = [p for p in parts if p.status_code not in [200, 202]] + failures = [p for p in parts if not (200 <= p.status_code < 300)] if failures: error = PartialBatchErrorException( message="There is a partial failure in the batch operation.", response=response, parts=iter(parts) ) - error.failed_operations = failures raise error return iter(parts) except StorageErrorException as error: diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py index 24a7c00ac773..da11c18d4b1c 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py @@ -129,14 +129,13 @@ async def _batch_send( failures = [] async for part in parts: parts_list.append(part) - if part.status_code not in [200, 202]: + if not (200 <= part.status_code < 300): failures.append(part) if failures: error = PartialBatchErrorException( message="There is a partial failure in the batch operation.", response=response, parts=AsyncList(parts_list) ) - error.failed_operations = failures raise error return AsyncList(parts_list) except StorageErrorException as error: diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py b/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py index 7bb83215e7bd..8480f96927d4 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py @@ -846,6 +846,7 @@ async def delete_blobs( # pylint: disable=arguments-differ timeout=timeout, **kwargs ) + options.update({'raise_on_any_failure': kwargs.pop('raise_on_any_failure', True)}) query_parameters, header_parameters = self._generate_delete_blobs_options(**options) # To pass kwargs to "_batch_send", we need to remove anything that was # in the Autorest signature for Autorest, otherwise transport will be upset diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/blob_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/blob_client.py index 7c5266cf44a9..958eeb28bdec 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/blob_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/blob_client.py @@ -723,7 +723,6 @@ def _generic_delete_blob_options(delete_snapshots=False, **kwargs): delete_snapshots = DeleteSnapshotsOptionType(delete_snapshots) options = { 'timeout': kwargs.pop('timeout', None), - 'raise_on_any_failure': kwargs.pop('raise_on_any_failure', True), 'delete_snapshots': delete_snapshots or None, 'lease_access_conditions': access_conditions, 'modified_access_conditions': mod_conditions} diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py index 642225c151dc..edfb5fd2a1e0 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py @@ -1108,6 +1108,7 @@ def delete_blobs(self, *blobs, **kwargs): options = BlobClient._generic_delete_blob_options( # pylint: disable=protected-access **kwargs ) + options.update({'raise_on_any_failure': kwargs.pop('raise_on_any_failure', True)}) query_parameters, header_parameters = self._generate_delete_blobs_options(**options) # To pass kwargs to "_batch_send", we need to remove anything that was # in the Autorest signature for Autorest, otherwise transport will be upset diff --git a/sdk/storage/azure-storage-blob/tests/test_container.py b/sdk/storage/azure-storage-blob/tests/test_container.py index b36ab0f70f39..db8f7aa55121 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container.py +++ b/sdk/storage/azure-storage-blob/tests/test_container.py @@ -1007,8 +1007,9 @@ def test_delete_blobs_simple(self): assert response[2].status_code == 202 @pytest.mark.skipif(sys.version_info < (3, 0), reason="Batch not supported on Python 2.7") - @record def test_delete_blobs_simple_no_raise(self): + if TestMode.need_recording_file(self.test_mode): + return # Arrange container = self._create_container() data = b'hello world' diff --git a/sdk/storage/azure-storage-blob/tests/test_container_async.py b/sdk/storage/azure-storage-blob/tests/test_container_async.py index 84e7fadea3c0..2a6794b2bd42 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_container_async.py @@ -1250,6 +1250,8 @@ async def _test_delete_blobs_simple(self): @record def test_delete_blobs_simple_no_raise(self): + if TestMode.need_recording_file(self.test_mode): + return loop = asyncio.get_event_loop() loop.run_until_complete(self._test_delete_blobs_simple()) From 5465e8bc9fe318a206a525f96bd9e33983271a76 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Fri, 18 Oct 2019 18:37:30 -0700 Subject: [PATCH 05/11] oops --- .../azure/storage/blob/aio/container_client_async.py | 3 ++- .../azure-storage-blob/azure/storage/blob/container_client.py | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py b/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py index 8480f96927d4..9c35522a5425 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/aio/container_client_async.py @@ -839,6 +839,7 @@ async def delete_blobs( # pylint: disable=arguments-differ :return: An async iterator of responses, one for each blob in order :rtype: asynciterator[~azure.core.pipeline.transport.AsyncHttpResponse] """ + raise_on_any_failure = kwargs.pop('raise_on_any_failure', True) timeout = kwargs.pop('timeout', None) options = BlobClient._generic_delete_blob_options( # pylint: disable=protected-access delete_snapshots=delete_snapshots, @@ -846,7 +847,7 @@ async def delete_blobs( # pylint: disable=arguments-differ timeout=timeout, **kwargs ) - options.update({'raise_on_any_failure': kwargs.pop('raise_on_any_failure', True)}) + options.update({'raise_on_any_failure': raise_on_any_failure}) query_parameters, header_parameters = self._generate_delete_blobs_options(**options) # To pass kwargs to "_batch_send", we need to remove anything that was # in the Autorest signature for Autorest, otherwise transport will be upset diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py index edfb5fd2a1e0..0349ba1e41c4 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/container_client.py @@ -1105,10 +1105,11 @@ def delete_blobs(self, *blobs, **kwargs): :return: An iterator of responses, one for each blob in order :rtype: iterator[~azure.core.pipeline.transport.HttpResponse] """ + raise_on_any_failure = kwargs.pop('raise_on_any_failure', True) options = BlobClient._generic_delete_blob_options( # pylint: disable=protected-access **kwargs ) - options.update({'raise_on_any_failure': kwargs.pop('raise_on_any_failure', True)}) + options.update({'raise_on_any_failure': raise_on_any_failure}) query_parameters, header_parameters = self._generate_delete_blobs_options(**options) # To pass kwargs to "_batch_send", we need to remove anything that was # in the Autorest signature for Autorest, otherwise transport will be upset From e8edc379db424bc8f2cc69590766c74585ffb563 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Mon, 21 Oct 2019 09:26:09 -0700 Subject: [PATCH 06/11] comments + lint --- .../azure/storage/blob/_shared/base_client.py | 2 +- .../storage/blob/_shared/base_client_async.py | 23 +++++++++---------- .../storage/blob/_shared/response_handlers.py | 9 +++----- .../tests/test_container.py | 13 ++++------- 4 files changed, 20 insertions(+), 27 deletions(-) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py index 9bb406901488..560737ae40b5 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py @@ -224,7 +224,7 @@ def _batch_send( raise HttpResponseError(response=response) parts = response.parts() if raise_on_any_failure: - failures = [p for p in parts if not (200 <= p.status_code < 300)] + failures = [p for p in parts if not 200 <= p.status_code < 300] if failures: error = PartialBatchErrorException( message="There is a partial failure in the batch operation.", diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py index cad4e2cc8ff0..9a485466701f 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py @@ -128,18 +128,17 @@ async def _batch_send( raise HttpResponseError(response=response) parts = response.parts() # Return an AsyncIterator parts_list = [] - if raise_on_any_failure: - failures = [] - async for part in parts: - parts_list.append(part) - if not (200 <= part.status_code < 300): - failures.append(part) - if failures: - error = PartialBatchErrorException( - message="There is a partial failure in the batch operation.", - response=response, parts=AsyncList(parts_list) - ) - raise error + failures = [] + async for part in parts: + parts_list.append(part) + if not 200 <= part.status_code < 300: + failures.append(part) + if raise_on_any_failure and failures: + error = PartialBatchErrorException( + message="There is a partial failure in the batch operation.", + response=response, parts=AsyncList(parts_list) + ) + raise error return AsyncList(parts_list) except StorageErrorException as error: process_storage_error(error) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py index 4332e9183dc5..5562df05004e 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py @@ -34,17 +34,14 @@ class PartialBatchErrorException(HttpResponseError): """There is a partial failure in batch operations. - :param deserialize: A deserializer + :param message: The message of the exception. :param response: Server response to be deserialized. + :param parts: An iterable of the parts in multipart response. """ def __init__(self, message, response, parts): - - self.response = response self.parts = parts - self.failed_operations = None - self.message = message - super(PartialBatchErrorException, self).__init__(message=self.message, response=response) + super(PartialBatchErrorException, self).__init__(message=message, response=response) def parse_length_from_content_range(content_range): diff --git a/sdk/storage/azure-storage-blob/tests/test_container.py b/sdk/storage/azure-storage-blob/tests/test_container.py index 4b3991761172..cae93eec5235 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container.py +++ b/sdk/storage/azure-storage-blob/tests/test_container.py @@ -1116,14 +1116,11 @@ def test_standard_blob_tier_set_tier_api_batch(self): assert not blob_ref2.blob_tier_inferred assert blob_ref2.blob_tier_change_time is not None - try: - response = container.delete_blobs( - 'blob1', - 'blob2', - 'blob3', - ) - except: - pass + response = container.delete_blobs( + 'blob1', + 'blob2', + 'blob3', + ) @pytest.mark.skip(reason="Wasn't able to get premium account with batch enabled") # once we have premium tests, still we don't want to test Py 2.7 From 5eb49239d76112bb45b055452abe813fea393976 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Mon, 21 Oct 2019 10:11:34 -0700 Subject: [PATCH 07/11] some optimization --- .../storage/blob/_shared/base_client_async.py | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py index 9a485466701f..2f9faac9364e 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py @@ -129,17 +129,19 @@ async def _batch_send( parts = response.parts() # Return an AsyncIterator parts_list = [] failures = [] - async for part in parts: - parts_list.append(part) - if not 200 <= part.status_code < 300: - failures.append(part) - if raise_on_any_failure and failures: - error = PartialBatchErrorException( - message="There is a partial failure in the batch operation.", - response=response, parts=AsyncList(parts_list) - ) - raise error - return AsyncList(parts_list) + if raise_on_any_failure: + async for part in parts: + parts_list.append(part) + if not 200 <= part.status_code < 300: + failures.append(part) + if failures: + error = PartialBatchErrorException( + message="There is a partial failure in the batch operation.", + response=response, parts=AsyncList(parts_list) + ) + raise error + return AsyncList(parts_list) + return parts except StorageErrorException as error: process_storage_error(error) From efd00f8cb207976ca4dcef0ccca30dd12ee37662 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Mon, 21 Oct 2019 10:19:08 -0700 Subject: [PATCH 08/11] history --- sdk/storage/azure-storage-blob/HISTORY.md | 1 + .../azure/storage/blob/_shared/base_client_async.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-blob/HISTORY.md b/sdk/storage/azure-storage-blob/HISTORY.md index b4567c2f91b4..589ad149ff7a 100644 --- a/sdk/storage/azure-storage-blob/HISTORY.md +++ b/sdk/storage/azure-storage-blob/HISTORY.md @@ -24,6 +24,7 @@ - `Logging` has been renamed to `BlobAnalyticsLogging`. - All operations that take Etag conditional parameters (`if_match` and `if_none_match`) now take explicit `etag` and `match_condition` parameters, where `etag` is the Etag value, and `match_condition` is an instance of `azure.core.MatchConditions`. - The `generate_shared_access_signature` methods on each of `BlobServiceClient`, `ContainerClient` and `BlobClient` have been replaced by module level functions `generate_account_sas`, `generate_container_sas` and `generate_blob_sas`. +- The batch APIs now have an additional keyword only argument `raise_on_any_failure` which defaults to True. This will raise an error even if there's a partial batch failure. **New features** diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py index 2f9faac9364e..69f679a8345d 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py @@ -134,7 +134,7 @@ async def _batch_send( parts_list.append(part) if not 200 <= part.status_code < 300: failures.append(part) - if failures: + if failures: error = PartialBatchErrorException( message="There is a partial failure in the batch operation.", response=response, parts=AsyncList(parts_list) From 4fd94213d10b82f3eff0ce41185c3363a093061f Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Mon, 21 Oct 2019 11:37:16 -0700 Subject: [PATCH 09/11] comments --- .../azure/storage/blob/__init__.py | 4 +- .../azure/storage/blob/_shared/base_client.py | 11 +- .../storage/blob/_shared/base_client_async.py | 9 +- .../storage/blob/_shared/response_handlers.py | 2 +- ...ner.test_delete_blobs_simple_no_raise.yaml | 530 ++++++++++++++++++ .../tests/test_container.py | 21 +- .../tests/test_container_async.py | 11 +- 7 files changed, 558 insertions(+), 30 deletions(-) create mode 100644 sdk/storage/azure-storage-blob/tests/recordings/test_container.test_delete_blobs_simple_no_raise.yaml diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/__init__.py b/sdk/storage/azure-storage-blob/azure/storage/blob/__init__.py index 8e1f2c6354c6..a26a856358cd 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/__init__.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/__init__.py @@ -15,6 +15,7 @@ from .download import StorageStreamDownloader from ._shared_access_signature import generate_account_sas, generate_container_sas, generate_blob_sas from ._shared.policies import ExponentialRetry, LinearRetry +from ._shared.response_handlers import PartialBatchErrorException from ._shared.models import( LocationMode, ResourceTypes, @@ -203,5 +204,6 @@ def download_blob_from_url( 'RehydratePriority', 'generate_account_sas', 'generate_container_sas', - 'generate_blob_sas' + 'generate_blob_sas', + 'PartialBatchErrorException' ] diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py index 560737ae40b5..744f0a404796 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py @@ -224,16 +224,17 @@ def _batch_send( raise HttpResponseError(response=response) parts = response.parts() if raise_on_any_failure: - failures = [p for p in parts if not 200 <= p.status_code < 300] - if failures: + parts = list(response.parts()) + if any(p for p in parts if not 200 <= p.status_code < 300): error = PartialBatchErrorException( message="There is a partial failure in the batch operation.", - response=response, parts=iter(parts) + response=response, parts=parts ) raise error - return iter(parts) + return iter(parts) + return parts except StorageErrorException as error: - process_storage_error(error) + process_storage_error(error) class TransportWrapper(HttpTransport): """Wrapper class that ensures that an inner client created diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py index 69f679a8345d..a795e5ed7655 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client_async.py @@ -127,17 +127,14 @@ async def _batch_send( if response.status_code not in [202]: raise HttpResponseError(response=response) parts = response.parts() # Return an AsyncIterator - parts_list = [] - failures = [] if raise_on_any_failure: + parts_list = [] async for part in parts: parts_list.append(part) - if not 200 <= part.status_code < 300: - failures.append(part) - if failures: + if any(p for p in parts_list if not 200 <= p.status_code < 300): error = PartialBatchErrorException( message="There is a partial failure in the batch operation.", - response=response, parts=AsyncList(parts_list) + response=response, parts=parts_list ) raise error return AsyncList(parts_list) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py index 5562df05004e..ce625d589504 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/response_handlers.py @@ -36,7 +36,7 @@ class PartialBatchErrorException(HttpResponseError): :param message: The message of the exception. :param response: Server response to be deserialized. - :param parts: An iterable of the parts in multipart response. + :param parts: A list of the parts in multipart response. """ def __init__(self, message, response, parts): diff --git a/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_delete_blobs_simple_no_raise.yaml b/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_delete_blobs_simple_no_raise.yaml new file mode 100644 index 000000000000..6f91c6939c1a --- /dev/null +++ b/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_delete_blobs_simple_no_raise.yaml @@ -0,0 +1,530 @@ +interactions: +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 52637c46-f42e-11e9-beca-2816a845e8c6 + x-ms-date: + - Mon, 21 Oct 2019 18:12:19 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containere26513ac?restype=container + response: + body: + string: '' + headers: + Content-Length: + - '0' + Date: + - Mon, 21 Oct 2019 18:12:19 GMT + ETag: + - '"0x8D7565236B58A6D"' + Last-Modified: + - Mon, 21 Oct 2019 18:12:20 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-request-id: + - 2b936bff-f01e-00d3-0a3b-88dba5000000 + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - 5294cc0c-f42e-11e9-8f00-2816a845e8c6 + x-ms-date: + - Mon, 21 Oct 2019 18:12:20 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containere26513ac/blob1 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Mon, 21 Oct 2019 18:12:19 GMT + ETag: + - '"0x8D7565236C44587"' + Last-Modified: + - Mon, 21 Oct 2019 18:12:20 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - 2b936c18-f01e-00d3-213b-88dba5000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - 52a36536-f42e-11e9-a141-2816a845e8c6 + x-ms-date: + - Mon, 21 Oct 2019 18:12:20 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containere26513ac/blob2 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Mon, 21 Oct 2019 18:12:19 GMT + ETag: + - '"0x8D7565236D6985B"' + Last-Modified: + - Mon, 21 Oct 2019 18:12:20 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - 2b936c2c-f01e-00d3-353b-88dba5000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - 52b5629a-f42e-11e9-b59f-2816a845e8c6 + x-ms-date: + - Mon, 21 Oct 2019 18:12:20 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containere26513ac/blob3 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Mon, 21 Oct 2019 18:12:19 GMT + ETag: + - '"0x8D7565236E7D992"' + Last-Modified: + - Mon, 21 Oct 2019 18:12:20 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - 2b936c49-f01e-00d3-4f3b-88dba5000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: "--===============2017407619==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: + binary\r\nContent-ID: 0\r\n\r\nDELETE /containere26513ac/blob1? HTTP/1.1\r\nx-ms-date: + Mon, 21 Oct 2019 18:12:20 GMT\r\nx-ms-client-request-id: 52c402b4-f42e-11e9-82d8-2816a845e8c6\r\nAuthorization: + SharedKey blobstoragename:FyRRNk130v84VIOnuTsYpqDFjO8JYcqJ8xsZopRTWvk=\r\n\r\n\r\n--===============2017407619==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 1\r\n\r\nDELETE + /containere26513ac/blob2? HTTP/1.1\r\nx-ms-date: Mon, 21 Oct 2019 18:12:20 GMT\r\nx-ms-client-request-id: + 52c402b5-f42e-11e9-9ea3-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:hLSp2jkYIcBNi7tD+XU65aZ+hz/Kg+RgeiQHnKGIebc=\r\n\r\n\r\n--===============2017407619==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 2\r\n\r\nDELETE + /containere26513ac/blob3? HTTP/1.1\r\nx-ms-date: Mon, 21 Oct 2019 18:12:20 GMT\r\nx-ms-client-request-id: + 52c402b6-f42e-11e9-927e-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:Y8IgZLgnv/2E2SL9wjqhxb9U3VvSme6ya4g0HPaKaXw=\r\n\r\n\r\n--===============2017407619==--\r\n" + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1071' + Content-Type: + - multipart/mixed; boundary================2017407619== + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - 52c8c55c-f42e-11e9-9eb3-2816a845e8c6 + x-ms-date: + - Mon, 21 Oct 2019 18:12:20 GMT + x-ms-version: + - '2019-02-02' + method: POST + uri: https://blobstoragename.blob.core.windows.net/?comp=batch + response: + body: + string: "--batchresponse_b3e72c3c-d3fd-4822-ad37-e52c4ff02aa2\r\nContent-Type: + application/http\r\nContent-ID: 0\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-status: + pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: 2b936c81-f01e-00d3-023b-88dba51eddc6\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_b3e72c3c-d3fd-4822-ad37-e52c4ff02aa2\r\nContent-Type: + application/http\r\nContent-ID: 1\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-status: + pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: 2b936c81-f01e-00d3-023b-88dba51eddc8\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_b3e72c3c-d3fd-4822-ad37-e52c4ff02aa2\r\nContent-Type: + application/http\r\nContent-ID: 2\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-status: + pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: 2b936c81-f01e-00d3-023b-88dba51eddc9\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_b3e72c3c-d3fd-4822-ad37-e52c4ff02aa2--" + headers: + Content-Type: + - multipart/mixed; boundary=batchresponse_b3e72c3c-d3fd-4822-ad37-e52c4ff02aa2 + Date: + - Mon, 21 Oct 2019 18:12:19 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Transfer-Encoding: + - chunked + x-ms-request-id: + - 2b936c81-f01e-00d3-023b-88dba5000000 + x-ms-version: + - '2019-02-02' + status: + code: 202 + message: Accepted +- request: + body: null + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - b75fb31e-f42e-11e9-8090-2816a845e8c6 + x-ms-date: + - Mon, 21 Oct 2019 18:15:09 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containere26513ac?restype=container + response: + body: + string: '' + headers: + Content-Length: + - '0' + Date: + - Mon, 21 Oct 2019 18:15:09 GMT + ETag: + - '"0x8D756529BCAD2D3"' + Last-Modified: + - Mon, 21 Oct 2019 18:15:09 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-request-id: + - e6bc8951-601e-005e-1d3b-889703000000 + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - b7a9cd80-f42e-11e9-affa-2816a845e8c6 + x-ms-date: + - Mon, 21 Oct 2019 18:15:09 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containere26513ac/blob1 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Mon, 21 Oct 2019 18:15:09 GMT + ETag: + - '"0x8D756529BD91349"' + Last-Modified: + - Mon, 21 Oct 2019 18:15:09 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - e6bc8986-601e-005e-473b-889703000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - b7b91fdc-f42e-11e9-a715-2816a845e8c6 + x-ms-date: + - Mon, 21 Oct 2019 18:15:09 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containere26513ac/blob2 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Mon, 21 Oct 2019 18:15:09 GMT + ETag: + - '"0x8D756529BEAA2A9"' + Last-Modified: + - Mon, 21 Oct 2019 18:15:09 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - e6bc89bd-601e-005e-723b-889703000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: hello world + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + If-None-Match: + - '*' + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-client-request-id: + - b7cacdba-f42e-11e9-8bdb-2816a845e8c6 + x-ms-date: + - Mon, 21 Oct 2019 18:15:10 GMT + x-ms-version: + - '2019-02-02' + method: PUT + uri: https://blobstoragename.blob.core.windows.net/containere26513ac/blob3 + response: + body: + string: '' + headers: + Content-Length: + - '0' + Content-MD5: + - XrY7u+Ae7tCTyyK7j1rNww== + Date: + - Mon, 21 Oct 2019 18:15:09 GMT + ETag: + - '"0x8D756529BFCF57D"' + Last-Modified: + - Mon, 21 Oct 2019 18:15:10 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-id: + - e6bc89ee-601e-005e-1f3b-889703000000 + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2019-02-02' + status: + code: 201 + message: Created +- request: + body: "--===============0568664881==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: + binary\r\nContent-ID: 0\r\n\r\nDELETE /containere26513ac/blob1? HTTP/1.1\r\nx-ms-date: + Mon, 21 Oct 2019 18:15:10 GMT\r\nx-ms-client-request-id: b7db548c-f42e-11e9-ba1a-2816a845e8c6\r\nAuthorization: + SharedKey blobstoragename:2vBnKG01VLAv+HLxMM3r2S9lxsxziaThddvntW6XAtI=\r\n\r\n\r\n--===============0568664881==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 1\r\n\r\nDELETE + /containere26513ac/blob2? HTTP/1.1\r\nx-ms-date: Mon, 21 Oct 2019 18:15:10 GMT\r\nx-ms-client-request-id: + b7db7b5c-f42e-11e9-ab7f-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:iFluB0V/IUp4QVQLYJXJfBr3NXNTlk95zcThY9ZfPqA=\r\n\r\n\r\n--===============0568664881==\r\nContent-Type: + application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 2\r\n\r\nDELETE + /containere26513ac/blob3? HTTP/1.1\r\nx-ms-date: Mon, 21 Oct 2019 18:15:10 GMT\r\nx-ms-client-request-id: + b7dba292-f42e-11e9-8ee6-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:kNBaw0HoVj+8+ZglyIY8lW040LghpKOWc9kWm/+lLbs=\r\n\r\n\r\n--===============0568664881==--\r\n" + headers: + Accept: + - '*/*' + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '1071' + Content-Type: + - multipart/mixed; boundary================0568664881== + User-Agent: + - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) + x-ms-client-request-id: + - b7df503e-f42e-11e9-83a8-2816a845e8c6 + x-ms-date: + - Mon, 21 Oct 2019 18:15:10 GMT + x-ms-version: + - '2019-02-02' + method: POST + uri: https://blobstoragename.blob.core.windows.net/?comp=batch + response: + body: + string: "--batchresponse_1f800cdd-d266-4d35-8b63-50c3476d97f5\r\nContent-Type: + application/http\r\nContent-ID: 0\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-status: + pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: e6bc8a40-601e-005e-6b3b-8897031eee2e\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_1f800cdd-d266-4d35-8b63-50c3476d97f5\r\nContent-Type: + application/http\r\nContent-ID: 1\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-status: + pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: e6bc8a40-601e-005e-6b3b-8897031eee30\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_1f800cdd-d266-4d35-8b63-50c3476d97f5\r\nContent-Type: + application/http\r\nContent-ID: 2\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-status: + pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: e6bc8a40-601e-005e-6b3b-8897031eee31\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_1f800cdd-d266-4d35-8b63-50c3476d97f5--" + headers: + Content-Type: + - multipart/mixed; boundary=batchresponse_1f800cdd-d266-4d35-8b63-50c3476d97f5 + Date: + - Mon, 21 Oct 2019 18:15:09 GMT + Server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + Transfer-Encoding: + - chunked + x-ms-request-id: + - e6bc8a40-601e-005e-6b3b-889703000000 + x-ms-version: + - '2019-02-02' + status: + code: 202 + message: Accepted +version: 1 diff --git a/sdk/storage/azure-storage-blob/tests/test_container.py b/sdk/storage/azure-storage-blob/tests/test_container.py index cae93eec5235..de17f9741a07 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container.py +++ b/sdk/storage/azure-storage-blob/tests/test_container.py @@ -27,6 +27,7 @@ StandardBlobTier, PremiumPageBlobTier, generate_container_sas, + PartialBatchErrorException ) from azure.identity import ClientSecretCredential @@ -1008,9 +1009,8 @@ def test_delete_blobs_simple(self): assert response[2].status_code == 202 @pytest.mark.skipif(sys.version_info < (3, 0), reason="Batch not supported on Python 2.7") + @record def test_delete_blobs_simple_no_raise(self): - if TestMode.need_recording_file(self.test_mode): - return # Arrange container = self._create_container() data = b'hello world' @@ -1061,7 +1061,7 @@ def test_delete_blobs_snapshot(self): 'blob3', delete_snapshots='only' ) - except HttpResponseError as err: + except PartialBatchErrorException as err: parts = list(err.parts) assert len(parts) == 3 assert parts[0].status_code == 202 @@ -1078,14 +1078,12 @@ def test_standard_blob_tier_set_tier_api_batch(self): tiers = [StandardBlobTier.Archive, StandardBlobTier.Cool, StandardBlobTier.Hot] for tier in tiers: - try: - response = container.delete_blobs( - 'blob1', - 'blob2', - 'blob3', - ) - except HttpResponseError as err: - response = err.parts + response = container.delete_blobs( + 'blob1', + 'blob2', + 'blob3', + raise_on_any_failure=False + ) blob = container.get_blob_client('blob1') data = b'hello world' blob.upload_blob(data) @@ -1120,6 +1118,7 @@ def test_standard_blob_tier_set_tier_api_batch(self): 'blob1', 'blob2', 'blob3', + raise_on_any_failure=False ) @pytest.mark.skip(reason="Wasn't able to get premium account with batch enabled") diff --git a/sdk/storage/azure-storage-blob/tests/test_container_async.py b/sdk/storage/azure-storage-blob/tests/test_container_async.py index a86fe45be60c..3d0b2c07aaf7 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_container_async.py @@ -28,7 +28,8 @@ ContainerSasPermissions, StandardBlobTier, PremiumPageBlobTier, - generate_container_sas + generate_container_sas, + PartialBatchErrorException ) from azure.storage.blob.aio import ( @@ -1250,7 +1251,7 @@ async def _test_delete_blobs_simple(self): assert response[2].status_code == 202 @record - def test_delete_blobs_simple_no_raise(self): + def test_delete_blobs_simple_no_raise_async(self): if TestMode.need_recording_file(self.test_mode): return loop = asyncio.get_event_loop() @@ -1309,10 +1310,8 @@ async def _test_delete_blobs_snapshot(self): 'blob3', delete_snapshots='only' )) - except HttpResponseError as err: - parts_list = [] - async for p in err.parts: - parts_list.append(p) + except PartialBatchErrorException as err: + parts_list = err.parts assert len(parts_list) == 3 assert parts_list[0].status_code == 202 assert parts_list[1].status_code == 404 # There was no snapshot From b463c8649f7b45af52b4f94d856887d6e7fcb340 Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Mon, 21 Oct 2019 11:39:48 -0700 Subject: [PATCH 10/11] lint --- .../azure/storage/blob/_shared/base_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py index 744f0a404796..1a6e77a9c5f8 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/base_client.py @@ -234,7 +234,7 @@ def _batch_send( return iter(parts) return parts except StorageErrorException as error: - process_storage_error(error) + process_storage_error(error) class TransportWrapper(HttpTransport): """Wrapper class that ensures that an inner client created From 33005e48658fb6c0d5861f4644a743ea05b934ce Mon Sep 17 00:00:00 2001 From: Rakshith Bhyravabhotla Date: Mon, 21 Oct 2019 12:27:48 -0700 Subject: [PATCH 11/11] recording --- ...ner.test_delete_blobs_simple_no_raise.yaml | 362 +++--------------- .../tests/test_container.py | 1 - 2 files changed, 49 insertions(+), 314 deletions(-) diff --git a/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_delete_blobs_simple_no_raise.yaml b/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_delete_blobs_simple_no_raise.yaml index 6f91c6939c1a..3226606d367d 100644 --- a/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_delete_blobs_simple_no_raise.yaml +++ b/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_delete_blobs_simple_no_raise.yaml @@ -13,13 +13,13 @@ interactions: User-Agent: - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) x-ms-client-request-id: - - 52637c46-f42e-11e9-beca-2816a845e8c6 + - c9c8f12c-f438-11e9-baff-2816a845e8c6 x-ms-date: - - Mon, 21 Oct 2019 18:12:19 GMT + - Mon, 21 Oct 2019 19:27:15 GMT x-ms-version: - '2019-02-02' method: PUT - uri: https://blobstoragename.blob.core.windows.net/containere26513ac?restype=container + uri: https://storagename.blob.core.windows.net/containere26513ac?restype=container response: body: string: '' @@ -27,15 +27,15 @@ interactions: Content-Length: - '0' Date: - - Mon, 21 Oct 2019 18:12:19 GMT + - Mon, 21 Oct 2019 19:27:15 GMT ETag: - - '"0x8D7565236B58A6D"' + - '"0x8D7565CAE1D8017"' Last-Modified: - - Mon, 21 Oct 2019 18:12:20 GMT + - Mon, 21 Oct 2019 19:27:15 GMT Server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-request-id: - - 2b936bff-f01e-00d3-0a3b-88dba5000000 + - 05fa205a-801e-0098-1145-88ea3f000000 x-ms-version: - '2019-02-02' status: @@ -61,13 +61,13 @@ interactions: x-ms-blob-type: - BlockBlob x-ms-client-request-id: - - 5294cc0c-f42e-11e9-8f00-2816a845e8c6 + - ca066e64-f438-11e9-8880-2816a845e8c6 x-ms-date: - - Mon, 21 Oct 2019 18:12:20 GMT + - Mon, 21 Oct 2019 19:27:15 GMT x-ms-version: - '2019-02-02' method: PUT - uri: https://blobstoragename.blob.core.windows.net/containere26513ac/blob1 + uri: https://storagename.blob.core.windows.net/containere26513ac/blob1 response: body: string: '' @@ -77,17 +77,17 @@ interactions: Content-MD5: - XrY7u+Ae7tCTyyK7j1rNww== Date: - - Mon, 21 Oct 2019 18:12:19 GMT + - Mon, 21 Oct 2019 19:27:15 GMT ETag: - - '"0x8D7565236C44587"' + - '"0x8D7565CAE344DCA"' Last-Modified: - - Mon, 21 Oct 2019 18:12:20 GMT + - Mon, 21 Oct 2019 19:27:15 GMT Server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-content-crc64: - vo7q9sPVKY0= x-ms-request-id: - - 2b936c18-f01e-00d3-213b-88dba5000000 + - 05fa2095-801e-0098-3f45-88ea3f000000 x-ms-request-server-encrypted: - 'true' x-ms-version: @@ -115,13 +115,13 @@ interactions: x-ms-blob-type: - BlockBlob x-ms-client-request-id: - - 52a36536-f42e-11e9-a141-2816a845e8c6 + - ca177786-f438-11e9-8167-2816a845e8c6 x-ms-date: - - Mon, 21 Oct 2019 18:12:20 GMT + - Mon, 21 Oct 2019 19:27:15 GMT x-ms-version: - '2019-02-02' method: PUT - uri: https://blobstoragename.blob.core.windows.net/containere26513ac/blob2 + uri: https://storagename.blob.core.windows.net/containere26513ac/blob2 response: body: string: '' @@ -131,17 +131,17 @@ interactions: Content-MD5: - XrY7u+Ae7tCTyyK7j1rNww== Date: - - Mon, 21 Oct 2019 18:12:19 GMT + - Mon, 21 Oct 2019 19:27:15 GMT ETag: - - '"0x8D7565236D6985B"' + - '"0x8D7565CAE4344A1"' Last-Modified: - - Mon, 21 Oct 2019 18:12:20 GMT + - Mon, 21 Oct 2019 19:27:15 GMT Server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-content-crc64: - vo7q9sPVKY0= x-ms-request-id: - - 2b936c2c-f01e-00d3-353b-88dba5000000 + - 05fa20bf-801e-0098-5f45-88ea3f000000 x-ms-request-server-encrypted: - 'true' x-ms-version: @@ -169,13 +169,13 @@ interactions: x-ms-blob-type: - BlockBlob x-ms-client-request-id: - - 52b5629a-f42e-11e9-b59f-2816a845e8c6 + - ca26616e-f438-11e9-8d59-2816a845e8c6 x-ms-date: - - Mon, 21 Oct 2019 18:12:20 GMT + - Mon, 21 Oct 2019 19:27:15 GMT x-ms-version: - '2019-02-02' method: PUT - uri: https://blobstoragename.blob.core.windows.net/containere26513ac/blob3 + uri: https://storagename.blob.core.windows.net/containere26513ac/blob3 response: body: string: '' @@ -185,17 +185,17 @@ interactions: Content-MD5: - XrY7u+Ae7tCTyyK7j1rNww== Date: - - Mon, 21 Oct 2019 18:12:19 GMT + - Mon, 21 Oct 2019 19:27:15 GMT ETag: - - '"0x8D7565236E7D992"' + - '"0x8D7565CAE519F1D"' Last-Modified: - - Mon, 21 Oct 2019 18:12:20 GMT + - Mon, 21 Oct 2019 19:27:15 GMT Server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 x-ms-content-crc64: - vo7q9sPVKY0= x-ms-request-id: - - 2b936c49-f01e-00d3-4f3b-88dba5000000 + - 05fa20d5-801e-0098-7245-88ea3f000000 x-ms-request-server-encrypted: - 'true' x-ms-version: @@ -204,16 +204,16 @@ interactions: code: 201 message: Created - request: - body: "--===============2017407619==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: + body: "--===============0499579814==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 0\r\n\r\nDELETE /containere26513ac/blob1? HTTP/1.1\r\nx-ms-date: - Mon, 21 Oct 2019 18:12:20 GMT\r\nx-ms-client-request-id: 52c402b4-f42e-11e9-82d8-2816a845e8c6\r\nAuthorization: - SharedKey blobstoragename:FyRRNk130v84VIOnuTsYpqDFjO8JYcqJ8xsZopRTWvk=\r\n\r\n\r\n--===============2017407619==\r\nContent-Type: + Mon, 21 Oct 2019 19:27:15 GMT\r\nx-ms-client-request-id: ca352482-f438-11e9-b6c8-2816a845e8c6\r\nAuthorization: + SharedKey storagename:q4u3XQVy39ZtlRVgRbbwm57aQ5bG7sSVe5migY3yj+s=\r\n\r\n\r\n--===============0499579814==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 1\r\n\r\nDELETE - /containere26513ac/blob2? HTTP/1.1\r\nx-ms-date: Mon, 21 Oct 2019 18:12:20 GMT\r\nx-ms-client-request-id: - 52c402b5-f42e-11e9-9ea3-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:hLSp2jkYIcBNi7tD+XU65aZ+hz/Kg+RgeiQHnKGIebc=\r\n\r\n\r\n--===============2017407619==\r\nContent-Type: + /containere26513ac/blob2? HTTP/1.1\r\nx-ms-date: Mon, 21 Oct 2019 19:27:15 GMT\r\nx-ms-client-request-id: + ca354b82-f438-11e9-9602-2816a845e8c6\r\nAuthorization: SharedKey storagename:KD2jTEyaDPrgU+NQkF/0PtNwnZmK1RP1Hq0rjwniqlc=\r\n\r\n\r\n--===============0499579814==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 2\r\n\r\nDELETE - /containere26513ac/blob3? HTTP/1.1\r\nx-ms-date: Mon, 21 Oct 2019 18:12:20 GMT\r\nx-ms-client-request-id: - 52c402b6-f42e-11e9-927e-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:Y8IgZLgnv/2E2SL9wjqhxb9U3VvSme6ya4g0HPaKaXw=\r\n\r\n\r\n--===============2017407619==--\r\n" + /containere26513ac/blob3? HTTP/1.1\r\nx-ms-date: Mon, 21 Oct 2019 19:27:15 GMT\r\nx-ms-client-request-id: + ca359978-f438-11e9-b3df-2816a845e8c6\r\nAuthorization: SharedKey storagename:Jnn/BFigZHorBTId/p6hnIxsB92m2n0Ir7kzPRqohVM=\r\n\r\n\r\n--===============0499579814==--\r\n" headers: Accept: - '*/*' @@ -224,304 +224,40 @@ interactions: Content-Length: - '1071' Content-Type: - - multipart/mixed; boundary================2017407619== + - multipart/mixed; boundary================0499579814== User-Agent: - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) x-ms-client-request-id: - - 52c8c55c-f42e-11e9-9eb3-2816a845e8c6 + - ca3b88ca-f438-11e9-ba8a-2816a845e8c6 x-ms-date: - - Mon, 21 Oct 2019 18:12:20 GMT + - Mon, 21 Oct 2019 19:27:15 GMT x-ms-version: - '2019-02-02' method: POST - uri: https://blobstoragename.blob.core.windows.net/?comp=batch + uri: https://storagename.blob.core.windows.net/?comp=batch response: body: - string: "--batchresponse_b3e72c3c-d3fd-4822-ad37-e52c4ff02aa2\r\nContent-Type: + string: "--batchresponse_2efae71e-dd6b-4405-9321-a09cc8966f72\r\nContent-Type: application/http\r\nContent-ID: 0\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-status: - pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: 2b936c81-f01e-00d3-023b-88dba51eddc6\r\nx-ms-version: - 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_b3e72c3c-d3fd-4822-ad37-e52c4ff02aa2\r\nContent-Type: + pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: 05fa20f9-801e-0098-0e45-88ea3f1efca2\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_2efae71e-dd6b-4405-9321-a09cc8966f72\r\nContent-Type: application/http\r\nContent-ID: 1\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-status: - pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: 2b936c81-f01e-00d3-023b-88dba51eddc8\r\nx-ms-version: - 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_b3e72c3c-d3fd-4822-ad37-e52c4ff02aa2\r\nContent-Type: + pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: 05fa20f9-801e-0098-0e45-88ea3f1efca4\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_2efae71e-dd6b-4405-9321-a09cc8966f72\r\nContent-Type: application/http\r\nContent-ID: 2\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-status: - pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: 2b936c81-f01e-00d3-023b-88dba51eddc9\r\nx-ms-version: - 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_b3e72c3c-d3fd-4822-ad37-e52c4ff02aa2--" + pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: 05fa20f9-801e-0098-0e45-88ea3f1efca5\r\nx-ms-version: + 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_2efae71e-dd6b-4405-9321-a09cc8966f72--" headers: Content-Type: - - multipart/mixed; boundary=batchresponse_b3e72c3c-d3fd-4822-ad37-e52c4ff02aa2 + - multipart/mixed; boundary=batchresponse_2efae71e-dd6b-4405-9321-a09cc8966f72 Date: - - Mon, 21 Oct 2019 18:12:19 GMT + - Mon, 21 Oct 2019 19:27:15 GMT Server: - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 Transfer-Encoding: - chunked x-ms-request-id: - - 2b936c81-f01e-00d3-023b-88dba5000000 - x-ms-version: - - '2019-02-02' - status: - code: 202 - message: Accepted -- request: - body: null - headers: - Accept: - - '*/*' - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - Content-Length: - - '0' - User-Agent: - - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) - x-ms-client-request-id: - - b75fb31e-f42e-11e9-8090-2816a845e8c6 - x-ms-date: - - Mon, 21 Oct 2019 18:15:09 GMT - x-ms-version: - - '2019-02-02' - method: PUT - uri: https://blobstoragename.blob.core.windows.net/containere26513ac?restype=container - response: - body: - string: '' - headers: - Content-Length: - - '0' - Date: - - Mon, 21 Oct 2019 18:15:09 GMT - ETag: - - '"0x8D756529BCAD2D3"' - Last-Modified: - - Mon, 21 Oct 2019 18:15:09 GMT - Server: - - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 - x-ms-request-id: - - e6bc8951-601e-005e-1d3b-889703000000 - x-ms-version: - - '2019-02-02' - status: - code: 201 - message: Created -- request: - body: hello world - headers: - Accept: - - '*/*' - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - Content-Length: - - '11' - Content-Type: - - application/octet-stream - If-None-Match: - - '*' - User-Agent: - - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) - x-ms-blob-type: - - BlockBlob - x-ms-client-request-id: - - b7a9cd80-f42e-11e9-affa-2816a845e8c6 - x-ms-date: - - Mon, 21 Oct 2019 18:15:09 GMT - x-ms-version: - - '2019-02-02' - method: PUT - uri: https://blobstoragename.blob.core.windows.net/containere26513ac/blob1 - response: - body: - string: '' - headers: - Content-Length: - - '0' - Content-MD5: - - XrY7u+Ae7tCTyyK7j1rNww== - Date: - - Mon, 21 Oct 2019 18:15:09 GMT - ETag: - - '"0x8D756529BD91349"' - Last-Modified: - - Mon, 21 Oct 2019 18:15:09 GMT - Server: - - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 - x-ms-content-crc64: - - vo7q9sPVKY0= - x-ms-request-id: - - e6bc8986-601e-005e-473b-889703000000 - x-ms-request-server-encrypted: - - 'true' - x-ms-version: - - '2019-02-02' - status: - code: 201 - message: Created -- request: - body: hello world - headers: - Accept: - - '*/*' - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - Content-Length: - - '11' - Content-Type: - - application/octet-stream - If-None-Match: - - '*' - User-Agent: - - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) - x-ms-blob-type: - - BlockBlob - x-ms-client-request-id: - - b7b91fdc-f42e-11e9-a715-2816a845e8c6 - x-ms-date: - - Mon, 21 Oct 2019 18:15:09 GMT - x-ms-version: - - '2019-02-02' - method: PUT - uri: https://blobstoragename.blob.core.windows.net/containere26513ac/blob2 - response: - body: - string: '' - headers: - Content-Length: - - '0' - Content-MD5: - - XrY7u+Ae7tCTyyK7j1rNww== - Date: - - Mon, 21 Oct 2019 18:15:09 GMT - ETag: - - '"0x8D756529BEAA2A9"' - Last-Modified: - - Mon, 21 Oct 2019 18:15:09 GMT - Server: - - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 - x-ms-content-crc64: - - vo7q9sPVKY0= - x-ms-request-id: - - e6bc89bd-601e-005e-723b-889703000000 - x-ms-request-server-encrypted: - - 'true' - x-ms-version: - - '2019-02-02' - status: - code: 201 - message: Created -- request: - body: hello world - headers: - Accept: - - '*/*' - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - Content-Length: - - '11' - Content-Type: - - application/octet-stream - If-None-Match: - - '*' - User-Agent: - - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) - x-ms-blob-type: - - BlockBlob - x-ms-client-request-id: - - b7cacdba-f42e-11e9-8bdb-2816a845e8c6 - x-ms-date: - - Mon, 21 Oct 2019 18:15:10 GMT - x-ms-version: - - '2019-02-02' - method: PUT - uri: https://blobstoragename.blob.core.windows.net/containere26513ac/blob3 - response: - body: - string: '' - headers: - Content-Length: - - '0' - Content-MD5: - - XrY7u+Ae7tCTyyK7j1rNww== - Date: - - Mon, 21 Oct 2019 18:15:09 GMT - ETag: - - '"0x8D756529BFCF57D"' - Last-Modified: - - Mon, 21 Oct 2019 18:15:10 GMT - Server: - - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 - x-ms-content-crc64: - - vo7q9sPVKY0= - x-ms-request-id: - - e6bc89ee-601e-005e-1f3b-889703000000 - x-ms-request-server-encrypted: - - 'true' - x-ms-version: - - '2019-02-02' - status: - code: 201 - message: Created -- request: - body: "--===============0568664881==\r\nContent-Type: application/http\r\nContent-Transfer-Encoding: - binary\r\nContent-ID: 0\r\n\r\nDELETE /containere26513ac/blob1? HTTP/1.1\r\nx-ms-date: - Mon, 21 Oct 2019 18:15:10 GMT\r\nx-ms-client-request-id: b7db548c-f42e-11e9-ba1a-2816a845e8c6\r\nAuthorization: - SharedKey blobstoragename:2vBnKG01VLAv+HLxMM3r2S9lxsxziaThddvntW6XAtI=\r\n\r\n\r\n--===============0568664881==\r\nContent-Type: - application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 1\r\n\r\nDELETE - /containere26513ac/blob2? HTTP/1.1\r\nx-ms-date: Mon, 21 Oct 2019 18:15:10 GMT\r\nx-ms-client-request-id: - b7db7b5c-f42e-11e9-ab7f-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:iFluB0V/IUp4QVQLYJXJfBr3NXNTlk95zcThY9ZfPqA=\r\n\r\n\r\n--===============0568664881==\r\nContent-Type: - application/http\r\nContent-Transfer-Encoding: binary\r\nContent-ID: 2\r\n\r\nDELETE - /containere26513ac/blob3? HTTP/1.1\r\nx-ms-date: Mon, 21 Oct 2019 18:15:10 GMT\r\nx-ms-client-request-id: - b7dba292-f42e-11e9-8ee6-2816a845e8c6\r\nAuthorization: SharedKey blobstoragename:kNBaw0HoVj+8+ZglyIY8lW040LghpKOWc9kWm/+lLbs=\r\n\r\n\r\n--===============0568664881==--\r\n" - headers: - Accept: - - '*/*' - Accept-Encoding: - - gzip, deflate - Connection: - - keep-alive - Content-Length: - - '1071' - Content-Type: - - multipart/mixed; boundary================0568664881== - User-Agent: - - azsdk-python-storage-blob/12.0.0b4 Python/3.7.3 (Windows-10-10.0.17763-SP0) - x-ms-client-request-id: - - b7df503e-f42e-11e9-83a8-2816a845e8c6 - x-ms-date: - - Mon, 21 Oct 2019 18:15:10 GMT - x-ms-version: - - '2019-02-02' - method: POST - uri: https://blobstoragename.blob.core.windows.net/?comp=batch - response: - body: - string: "--batchresponse_1f800cdd-d266-4d35-8b63-50c3476d97f5\r\nContent-Type: - application/http\r\nContent-ID: 0\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-status: - pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: e6bc8a40-601e-005e-6b3b-8897031eee2e\r\nx-ms-version: - 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_1f800cdd-d266-4d35-8b63-50c3476d97f5\r\nContent-Type: - application/http\r\nContent-ID: 1\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-status: - pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: e6bc8a40-601e-005e-6b3b-8897031eee30\r\nx-ms-version: - 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_1f800cdd-d266-4d35-8b63-50c3476d97f5\r\nContent-Type: - application/http\r\nContent-ID: 2\r\n\r\nHTTP/1.1 202 Accepted\r\nx-ms-delete-status: - pending\r\nx-ms-delete-type-permanent: false\r\nx-ms-request-id: e6bc8a40-601e-005e-6b3b-8897031eee31\r\nx-ms-version: - 2019-02-02\r\nServer: Windows-Azure-Blob/1.0\r\n\r\n--batchresponse_1f800cdd-d266-4d35-8b63-50c3476d97f5--" - headers: - Content-Type: - - multipart/mixed; boundary=batchresponse_1f800cdd-d266-4d35-8b63-50c3476d97f5 - Date: - - Mon, 21 Oct 2019 18:15:09 GMT - Server: - - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 - Transfer-Encoding: - - chunked - x-ms-request-id: - - e6bc8a40-601e-005e-6b3b-889703000000 + - 05fa20f9-801e-0098-0e45-88ea3f000000 x-ms-version: - '2019-02-02' status: diff --git a/sdk/storage/azure-storage-blob/tests/test_container.py b/sdk/storage/azure-storage-blob/tests/test_container.py index de17f9741a07..b22e6e1ce07b 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container.py +++ b/sdk/storage/azure-storage-blob/tests/test_container.py @@ -1029,7 +1029,6 @@ def test_delete_blobs_simple_no_raise(self): 'blob3', raise_on_any_failure=False ) - response = list(response) assert len(response) == 3 assert response[0].status_code == 202 assert response[1].status_code == 202