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 d2caf7a5a8e5..b1a8a21946d4 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 @@ -743,7 +743,8 @@ def list_blobs(self, name_starts_with=None, include=None, **kwargs): begin with the specified prefix. :param list[str] or str include: Specifies one or more additional datasets to include in the response. - Options include: 'snapshots', 'metadata', 'uncommittedblobs', 'copy', 'deleted', 'tags'. + Options include: 'snapshots', 'metadata', 'uncommittedblobs', 'copy', 'deleted', 'deletedwithversions', + 'tags', 'versions'. :keyword int timeout: The timeout parameter is expressed in seconds. :returns: An iterable (auto-paging) response of BlobProperties. diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_deserialize.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_deserialize.py index dff39536572d..e54cccc57bcc 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_deserialize.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_deserialize.py @@ -153,6 +153,7 @@ def get_blob_properties_from_generated_code(generated): blob.tags = parse_tags(generated.blob_tags) # pylint: disable=protected-access blob.object_replication_source_properties = deserialize_ors_policies(generated.object_replication_metadata) blob.last_accessed_on = generated.properties.last_accessed_on + blob.has_versions_only = generated.has_versions_only return blob diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/models/_models.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/models/_models.py index 8e2e604c746f..7c4362edf615 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/models/_models.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/models/_models.py @@ -280,6 +280,7 @@ class BlobItemInternal(msrest.serialization.Model): 'metadata': {'key': 'Metadata', 'type': 'BlobMetadata'}, 'blob_tags': {'key': 'BlobTags', 'type': 'BlobTags'}, 'object_replication_metadata': {'key': 'OrMetadata', 'type': '{str}'}, + 'has_versions_only': {'key': 'HasVersionsOnly', 'type': 'bool'}, } _xml_map = { 'name': 'Blob' diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/models/_models_py3.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/models/_models_py3.py index d10ef443f76c..50d17842a1f4 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/models/_models_py3.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/models/_models_py3.py @@ -311,6 +311,7 @@ class BlobItemInternal(msrest.serialization.Model): 'metadata': {'key': 'Metadata', 'type': 'BlobMetadata'}, 'blob_tags': {'key': 'BlobTags', 'type': 'BlobTags'}, 'object_replication_metadata': {'key': 'OrMetadata', 'type': '{str}'}, + 'has_versions_only': {'key': 'HasVersionsOnly', 'type': 'bool'}, } _xml_map = { 'name': 'Blob' diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_models.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_models.py index 1ddde2e46c5c..3529850cbd3d 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_models.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_models.py @@ -519,6 +519,10 @@ class BlobProperties(DictMixin): Key value pair of tags on this blob. .. versionadded:: 12.4.0 + :ivar bool has_versions_only: + A true value indicates the root blob is deleted + + .. versionadded:: 12.10.0 """ @@ -559,6 +563,7 @@ def __init__(self, **kwargs): self.last_accessed_on = kwargs.get('x-ms-last-access-time') self.tag_count = kwargs.get('x-ms-tag-count') self.tags = None + self.has_versions_only = None class FilteredBlob(DictMixin): diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_serialize.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_serialize.py index 8f6f265dce52..4eb3fb4ecfa0 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_serialize.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_serialize.py @@ -38,7 +38,8 @@ '2020-02-10', '2020-04-08', '2020-06-12', - '2020-08-04' + '2020-08-04', + '2020-10-02' ] 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 93cc87748e34..3efaa0dcb0d1 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 @@ -605,7 +605,8 @@ def list_blobs(self, name_starts_with=None, include=None, **kwargs): begin with the specified prefix. :param list[str] or str include: Specifies one or more additional datasets to include in the response. - Options include: 'snapshots', 'metadata', 'uncommittedblobs', 'copy', 'deleted', 'tags'. + Options include: 'snapshots', 'metadata', 'uncommittedblobs', 'copy', 'deleted', 'deletedwithversions', + 'tags', 'versions'. :keyword int timeout: The timeout parameter is expressed in seconds. :returns: An iterable (auto-paging) response of BlobProperties. diff --git a/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_list_blobs_include_deletedwithversion.yaml b/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_list_blobs_include_deletedwithversion.yaml new file mode 100644 index 000000000000..e31a7fbfdd84 --- /dev/null +++ b/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_list_blobs_include_deletedwithversion.yaml @@ -0,0 +1,524 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Fri, 04 Jun 2021 00:22:33 GMT + x-ms-version: + - '2020-10-02' + method: PUT + uri: https://storagename.blob.core.windows.net/containera8e61798?restype=container + response: + body: + string: "\uFEFFContainerAlreadyExistsThe + specified container already exists.\nRequestId:8202fa90-c01e-0059-1ed7-585d41000000\nTime:2021-06-04T00:22:34.3511114Z" + headers: + content-length: + - '230' + content-type: + - application/xml + date: + - Fri, 04 Jun 2021 00:22:33 GMT + server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-error-code: + - ContainerAlreadyExists + x-ms-version: + - '2020-10-02' + status: + code: 409 + message: The specified container already exists. +- request: + body: hello world + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-blob-content-disposition: + - inline + x-ms-blob-content-language: + - spanish + x-ms-blob-type: + - BlockBlob + x-ms-date: + - Fri, 04 Jun 2021 00:22:34 GMT + x-ms-meta-name: + - bob + x-ms-meta-number: + - '1' + x-ms-version: + - '2020-10-02' + method: PUT + uri: https://storagename.blob.core.windows.net/containera8e61798/blob1 + response: + body: + string: '' + headers: + content-length: + - '0' + content-md5: + - XrY7u+Ae7tCTyyK7j1rNww== + date: + - Fri, 04 Jun 2021 00:22:34 GMT + etag: + - '"0x8D926EED9C8EF9A"' + last-modified: + - Fri, 04 Jun 2021 00:22:34 GMT + server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2020-10-02' + x-ms-version-id: + - '2021-06-04T00:22:34.7532186Z' + status: + code: 201 + message: Created +- request: + body: abc + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '3' + Content-Type: + - application/octet-stream + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-date: + - Fri, 04 Jun 2021 00:22:34 GMT + x-ms-version: + - '2020-10-02' + method: PUT + uri: https://storagename.blob.core.windows.net/containera8e61798/blob1 + response: + body: + string: '' + headers: + content-length: + - '0' + content-md5: + - kAFQmDzST7DWlj99KOF/cg== + date: + - Fri, 04 Jun 2021 00:22:34 GMT + etag: + - '"0x8D926EED9DC2CFA"' + last-modified: + - Fri, 04 Jun 2021 00:22:34 GMT + server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - 6/rBP7vK5QU= + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2020-10-02' + x-ms-version-id: + - '2021-06-04T00:22:34.8803082Z' + status: + code: 201 + message: Created +- request: + body: cde + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '3' + Content-Type: + - application/octet-stream + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-date: + - Fri, 04 Jun 2021 00:22:34 GMT + x-ms-version: + - '2020-10-02' + method: PUT + uri: https://storagename.blob.core.windows.net/containera8e61798/blob1 + response: + body: + string: '' + headers: + content-length: + - '0' + content-md5: + - olbmszav3DjFZHicOZtRbA== + date: + - Fri, 04 Jun 2021 00:22:34 GMT + etag: + - '"0x8D926EED9EF6A5B"' + last-modified: + - Fri, 04 Jun 2021 00:22:35 GMT + server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - SsrIw8/pA7Y= + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2020-10-02' + x-ms-version-id: + - '2021-06-04T00:22:35.0063979Z' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '0' + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Fri, 04 Jun 2021 00:22:35 GMT + x-ms-version: + - '2020-10-02' + method: DELETE + uri: https://storagename.blob.core.windows.net/containera8e61798/blob1 + response: + body: + string: '' + headers: + content-length: + - '0' + date: + - Fri, 04 Jun 2021 00:22:34 GMT + server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-delete-type-permanent: + - 'false' + x-ms-version: + - '2020-10-02' + status: + code: 202 + message: Accepted +- request: + body: hello world + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-blob-content-disposition: + - inline + x-ms-blob-content-language: + - spanish + x-ms-blob-type: + - BlockBlob + x-ms-date: + - Fri, 04 Jun 2021 00:22:35 GMT + x-ms-meta-name: + - car + x-ms-meta-number: + - '2' + x-ms-version: + - '2020-10-02' + method: PUT + uri: https://storagename.blob.core.windows.net/containera8e61798/blob2 + response: + body: + string: '' + headers: + content-length: + - '0' + content-md5: + - XrY7u+Ae7tCTyyK7j1rNww== + date: + - Fri, 04 Jun 2021 00:22:34 GMT + etag: + - '"0x8D926EEDA1BD9AA"' + last-modified: + - Fri, 04 Jun 2021 00:22:35 GMT + server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2020-10-02' + x-ms-version-id: + - '2021-06-04T00:22:35.2976058Z' + status: + code: 201 + message: Created +- request: + body: hello world + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + Content-Length: + - '11' + Content-Type: + - application/octet-stream + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-blob-content-disposition: + - inline + x-ms-blob-content-language: + - spanish + x-ms-blob-type: + - BlockBlob + x-ms-date: + - Fri, 04 Jun 2021 00:22:35 GMT + x-ms-meta-name: + - car + x-ms-meta-number: + - '2' + x-ms-version: + - '2020-10-02' + method: PUT + uri: https://storagename.blob.core.windows.net/containera8e61798/blob3 + response: + body: + string: '' + headers: + content-length: + - '0' + content-md5: + - XrY7u+Ae7tCTyyK7j1rNww== + date: + - Fri, 04 Jun 2021 00:22:34 GMT + etag: + - '"0x8D926EEDA34BD55"' + last-modified: + - Fri, 04 Jun 2021 00:22:35 GMT + server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: + - vo7q9sPVKY0= + x-ms-request-server-encrypted: + - 'true' + x-ms-version: + - '2020-10-02' + x-ms-version-id: + - '2021-06-04T00:22:35.4607205Z' + status: + code: 201 + message: Created +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Fri, 04 Jun 2021 00:22:35 GMT + x-ms-version: + - '2020-10-02' + method: GET + uri: https://storagename.blob.core.windows.net/containera8e61798?restype=container&comp=list&include=deletedwithversions + response: + body: + string: "\uFEFFblob1trueFri, + 04 Jun 2021 00:22:35 GMTFri, 04 Jun 2021 00:22:35 + GMT0x8D926EED9EF6A5B0application/octet-streamolbmszav3DjFZHicOZtRbA==Fri, 04 Jun 2021 00:22:35 GMTBlockBlobHottrueunlockedavailabletrueblob22021-06-04T00:22:35.2976058ZtrueFri, + 04 Jun 2021 00:22:35 GMTFri, 04 Jun 2021 00:22:35 + GMT0x8D926EEDA1BD9AA11application/octet-streamspanishXrY7u+Ae7tCTyyK7j1rNww==inlineFri, 04 + Jun 2021 00:22:35 GMTBlockBlobHottrueunlockedavailabletrueblob32021-06-04T00:22:35.4607205ZtrueFri, + 04 Jun 2021 00:22:35 GMTFri, 04 Jun 2021 00:22:35 + GMT0x8D926EEDA34BD5511application/octet-streamspanishXrY7u+Ae7tCTyyK7j1rNww==inlineFri, 04 + Jun 2021 00:22:35 GMTBlockBlobHottrueunlockedavailabletrueblob6trueFri, + 04 Jun 2021 00:03:14 GMTFri, 04 Jun 2021 00:03:14 + GMT0x8D926EC2628399C0application/octet-streamolbmszav3DjFZHicOZtRbA==Fri, 04 Jun 2021 00:03:14 GMTBlockBlobHottrueunlockedavailabletrue" + headers: + content-type: + - application/xml + date: + - Fri, 04 Jun 2021 00:22:34 GMT + server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: + - chunked + x-ms-version: + - '2020-10-02' + status: + code: 200 + message: OK +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Fri, 04 Jun 2021 00:22:35 GMT + x-ms-range: + - bytes=0-33554431 + x-ms-version: + - '2020-10-02' + method: GET + uri: https://storagename.blob.core.windows.net/containera8e61798/blob1?versionid=2021-06-04T00%3A22%3A35.0063979Z + response: + body: + string: cde + headers: + accept-ranges: + - bytes + content-length: + - '3' + content-range: + - bytes 0-2/3 + content-type: + - application/octet-stream + date: + - Fri, 04 Jun 2021 00:22:35 GMT + etag: + - '"0x8D926EED9EF6A5B"' + last-modified: + - Fri, 04 Jun 2021 00:22:35 GMT + server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-blob-content-md5: + - olbmszav3DjFZHicOZtRbA== + x-ms-blob-type: + - BlockBlob + x-ms-creation-time: + - Fri, 04 Jun 2021 00:22:35 GMT + x-ms-server-encrypted: + - 'true' + x-ms-version: + - '2020-10-02' + x-ms-version-id: + - '2021-06-04T00:22:35.0063979Z' + status: + code: 206 + message: Partial Content +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Fri, 04 Jun 2021 00:22:35 GMT + x-ms-range: + - bytes=0-33554431 + x-ms-version: + - '2020-10-02' + method: GET + uri: https://storagename.blob.core.windows.net/containera8e61798/blob1?versionid=2021-06-04T00%3A22%3A34.7532186Z + response: + body: + string: hello world + headers: + accept-ranges: + - bytes + content-disposition: + - inline + content-language: + - spanish + content-length: + - '11' + content-range: + - bytes 0-10/11 + content-type: + - application/octet-stream + date: + - Fri, 04 Jun 2021 00:22:35 GMT + etag: + - '"0x8D926EED9C8EF9A"' + last-modified: + - Fri, 04 Jun 2021 00:22:34 GMT + server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-blob-content-md5: + - XrY7u+Ae7tCTyyK7j1rNww== + x-ms-blob-type: + - BlockBlob + x-ms-creation-time: + - Fri, 04 Jun 2021 00:22:34 GMT + x-ms-meta-name: + - bob + x-ms-meta-number: + - '1' + x-ms-server-encrypted: + - 'true' + x-ms-version: + - '2020-10-02' + x-ms-version-id: + - '2021-06-04T00:22:34.7532186Z' + status: + code: 206 + message: Partial Content +version: 1 diff --git a/sdk/storage/azure-storage-blob/tests/recordings/test_container_async.test_list_blobs_include_deletedwithversion_async.yaml b/sdk/storage/azure-storage-blob/tests/recordings/test_container_async.test_list_blobs_include_deletedwithversion_async.yaml new file mode 100644 index 000000000000..d70b34396475 --- /dev/null +++ b/sdk/storage/azure-storage-blob/tests/recordings/test_container_async.test_list_blobs_include_deletedwithversion_async.yaml @@ -0,0 +1,387 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Fri, 04 Jun 2021 00:22:45 GMT + x-ms-version: + - '2020-10-02' + method: PUT + uri: https://storagename.blob.core.windows.net/acontainere4ee1c92?restype=container + response: + body: + string: "\uFEFFContainerAlreadyExistsThe + specified container already exists.\nRequestId:7bc8288b-b01e-0031-13d7-583bd1000000\nTime:2021-06-04T00:22:45.4807498Z" + headers: + content-length: '230' + content-type: application/xml + date: Fri, 04 Jun 2021 00:22:44 GMT + server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-error-code: ContainerAlreadyExists + x-ms-version: '2020-10-02' + status: + code: 409 + message: The specified container already exists. + url: https://seanmcccanary3.blob.core.windows.net/acontainere4ee1c92?restype=container +- request: + body: hello world + headers: + Accept: + - application/xml + Content-Length: + - '11' + Content-Type: + - application/octet-stream + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-blob-content-disposition: + - inline + x-ms-blob-content-language: + - spanish + x-ms-blob-type: + - BlockBlob + x-ms-date: + - Fri, 04 Jun 2021 00:22:45 GMT + x-ms-meta-name: + - bob + x-ms-meta-number: + - '1' + x-ms-version: + - '2020-10-02' + method: PUT + uri: https://storagename.blob.core.windows.net/acontainere4ee1c92/blob1 + response: + body: + string: '' + headers: + content-length: '0' + content-md5: XrY7u+Ae7tCTyyK7j1rNww== + date: Fri, 04 Jun 2021 00:22:44 GMT + etag: '"0x8D926EEE0381268"' + last-modified: Fri, 04 Jun 2021 00:22:45 GMT + server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: vo7q9sPVKY0= + x-ms-request-server-encrypted: 'true' + x-ms-version: '2020-10-02' + x-ms-version-id: '2021-06-04T00:22:45.5478888Z' + status: + code: 201 + message: Created + url: https://seanmcccanary3.blob.core.windows.net/acontainere4ee1c92/blob1 +- request: + body: abc + headers: + Accept: + - application/xml + Content-Length: + - '3' + Content-Type: + - application/octet-stream + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-date: + - Fri, 04 Jun 2021 00:22:45 GMT + x-ms-version: + - '2020-10-02' + method: PUT + uri: https://storagename.blob.core.windows.net/acontainere4ee1c92/blob1 + response: + body: + string: '' + headers: + content-length: '0' + content-md5: kAFQmDzST7DWlj99KOF/cg== + date: Fri, 04 Jun 2021 00:22:44 GMT + etag: '"0x8D926EEE04162EA"' + last-modified: Fri, 04 Jun 2021 00:22:45 GMT + server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: 6/rBP7vK5QU= + x-ms-request-server-encrypted: 'true' + x-ms-version: '2020-10-02' + x-ms-version-id: '2021-06-04T00:22:45.6099322Z' + status: + code: 201 + message: Created + url: https://seanmcccanary3.blob.core.windows.net/acontainere4ee1c92/blob1 +- request: + body: cde + headers: + Accept: + - application/xml + Content-Length: + - '3' + Content-Type: + - application/octet-stream + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-blob-type: + - BlockBlob + x-ms-date: + - Fri, 04 Jun 2021 00:22:45 GMT + x-ms-version: + - '2020-10-02' + method: PUT + uri: https://storagename.blob.core.windows.net/acontainere4ee1c92/blob1 + response: + body: + string: '' + headers: + content-length: '0' + content-md5: olbmszav3DjFZHicOZtRbA== + date: Fri, 04 Jun 2021 00:22:44 GMT + etag: '"0x8D926EEE04B019A"' + last-modified: Fri, 04 Jun 2021 00:22:45 GMT + server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: SsrIw8/pA7Y= + x-ms-request-server-encrypted: 'true' + x-ms-version: '2020-10-02' + x-ms-version-id: '2021-06-04T00:22:45.6729770Z' + status: + code: 201 + message: Created + url: https://seanmcccanary3.blob.core.windows.net/acontainere4ee1c92/blob1 +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Fri, 04 Jun 2021 00:22:45 GMT + x-ms-version: + - '2020-10-02' + method: DELETE + uri: https://storagename.blob.core.windows.net/acontainere4ee1c92/blob1 + response: + body: + string: '' + headers: + content-length: '0' + date: Fri, 04 Jun 2021 00:22:44 GMT + server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-delete-type-permanent: 'false' + x-ms-version: '2020-10-02' + status: + code: 202 + message: Accepted + url: https://seanmcccanary3.blob.core.windows.net/acontainere4ee1c92/blob1 +- request: + body: hello world + headers: + Accept: + - application/xml + Content-Length: + - '11' + Content-Type: + - application/octet-stream + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-blob-content-disposition: + - inline + x-ms-blob-content-language: + - spanish + x-ms-blob-type: + - BlockBlob + x-ms-date: + - Fri, 04 Jun 2021 00:22:45 GMT + x-ms-meta-name: + - car + x-ms-meta-number: + - '2' + x-ms-version: + - '2020-10-02' + method: PUT + uri: https://storagename.blob.core.windows.net/acontainere4ee1c92/blob2 + response: + body: + string: '' + headers: + content-length: '0' + content-md5: XrY7u+Ae7tCTyyK7j1rNww== + date: Fri, 04 Jun 2021 00:22:45 GMT + etag: '"0x8D926EEE0625E6F"' + last-modified: Fri, 04 Jun 2021 00:22:45 GMT + server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: vo7q9sPVKY0= + x-ms-request-server-encrypted: 'true' + x-ms-version: '2020-10-02' + x-ms-version-id: '2021-06-04T00:22:45.8260863Z' + status: + code: 201 + message: Created + url: https://seanmcccanary3.blob.core.windows.net/acontainere4ee1c92/blob2 +- request: + body: hello world + headers: + Accept: + - application/xml + Content-Length: + - '11' + Content-Type: + - application/octet-stream + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-blob-content-disposition: + - inline + x-ms-blob-content-language: + - spanish + x-ms-blob-type: + - BlockBlob + x-ms-date: + - Fri, 04 Jun 2021 00:22:45 GMT + x-ms-meta-name: + - car + x-ms-meta-number: + - '2' + x-ms-version: + - '2020-10-02' + method: PUT + uri: https://storagename.blob.core.windows.net/acontainere4ee1c92/blob3 + response: + body: + string: '' + headers: + content-length: '0' + content-md5: XrY7u+Ae7tCTyyK7j1rNww== + date: Fri, 04 Jun 2021 00:22:45 GMT + etag: '"0x8D926EEE06B128C"' + last-modified: Fri, 04 Jun 2021 00:22:45 GMT + server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-content-crc64: vo7q9sPVKY0= + x-ms-request-server-encrypted: 'true' + x-ms-version: '2020-10-02' + x-ms-version-id: '2021-06-04T00:22:45.8841272Z' + status: + code: 201 + message: Created + url: https://seanmcccanary3.blob.core.windows.net/acontainere4ee1c92/blob3 +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Fri, 04 Jun 2021 00:22:45 GMT + x-ms-version: + - '2020-10-02' + method: GET + uri: https://storagename.blob.core.windows.net/acontainere4ee1c92?restype=container&comp=list&include=deletedwithversions + response: + body: + string: "\uFEFFblob1trueFri, + 04 Jun 2021 00:22:45 GMTFri, 04 Jun 2021 00:22:45 + GMT0x8D926EEE04B019A0application/octet-streamolbmszav3DjFZHicOZtRbA==Fri, 04 Jun 2021 00:22:45 GMTBlockBlobHottrueunlockedavailabletrueblob22021-06-04T00:22:45.8260863ZtrueFri, + 04 Jun 2021 00:22:45 GMTFri, 04 Jun 2021 00:22:45 + GMT0x8D926EEE0625E6F11application/octet-streamspanishXrY7u+Ae7tCTyyK7j1rNww==inlineFri, 04 + Jun 2021 00:22:45 GMTBlockBlobHottrueunlockedavailabletrueblob32021-06-04T00:22:45.8841272ZtrueFri, + 04 Jun 2021 00:22:45 GMTFri, 04 Jun 2021 00:22:45 + GMT0x8D926EEE06B128C11application/octet-streamspanishXrY7u+Ae7tCTyyK7j1rNww==inlineFri, 04 + Jun 2021 00:22:45 GMTBlockBlobHottrueunlockedavailabletrue" + headers: + content-type: application/xml + date: Fri, 04 Jun 2021 00:22:45 GMT + server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + transfer-encoding: chunked + x-ms-version: '2020-10-02' + status: + code: 200 + message: OK + url: https://seanmcccanary3.blob.core.windows.net/acontainere4ee1c92?restype=container&comp=list&include=deletedwithversions +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Fri, 04 Jun 2021 00:22:46 GMT + x-ms-range: + - bytes=0-33554431 + x-ms-version: + - '2020-10-02' + method: GET + uri: https://storagename.blob.core.windows.net/acontainere4ee1c92/blob1?versionid=2021-06-04T00:22:45.6729770Z + response: + body: + string: cde + headers: + accept-ranges: bytes + content-length: '3' + content-range: bytes 0-2/3 + content-type: application/octet-stream + date: Fri, 04 Jun 2021 00:22:45 GMT + etag: '"0x8D926EEE04B019A"' + last-modified: Fri, 04 Jun 2021 00:22:45 GMT + server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-blob-content-md5: olbmszav3DjFZHicOZtRbA== + x-ms-blob-type: BlockBlob + x-ms-creation-time: Fri, 04 Jun 2021 00:22:45 GMT + x-ms-server-encrypted: 'true' + x-ms-version: '2020-10-02' + x-ms-version-id: '2021-06-04T00:22:45.6729770Z' + status: + code: 206 + message: Partial Content + url: https://seanmcccanary3.blob.core.windows.net/acontainere4ee1c92/blob1?versionid=2021-06-04T00:22:45.6729770Z +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-blob/12.9.0b1 Python/3.7.3 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Fri, 04 Jun 2021 00:22:46 GMT + x-ms-range: + - bytes=0-33554431 + x-ms-version: + - '2020-10-02' + method: GET + uri: https://storagename.blob.core.windows.net/acontainere4ee1c92/blob1?versionid=2021-06-04T00:22:45.5478888Z + response: + body: + string: hello world + headers: + accept-ranges: bytes + content-disposition: inline + content-language: spanish + content-length: '11' + content-range: bytes 0-10/11 + content-type: application/octet-stream + date: Fri, 04 Jun 2021 00:22:45 GMT + etag: '"0x8D926EEE0381268"' + last-modified: Fri, 04 Jun 2021 00:22:45 GMT + server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-blob-content-md5: XrY7u+Ae7tCTyyK7j1rNww== + x-ms-blob-type: BlockBlob + x-ms-creation-time: Fri, 04 Jun 2021 00:22:45 GMT + x-ms-meta-name: bob + x-ms-meta-number: '1' + x-ms-server-encrypted: 'true' + x-ms-version: '2020-10-02' + x-ms-version-id: '2021-06-04T00:22:45.5478888Z' + status: + code: 206 + message: Partial Content + url: https://seanmcccanary3.blob.core.windows.net/acontainere4ee1c92/blob1?versionid=2021-06-04T00:22:45.5478888Z +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 4608f7a7bc17..3aa4f6d99384 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container.py +++ b/sdk/storage/azure-storage-blob/tests/test_container.py @@ -1083,6 +1083,41 @@ def test_list_blobs_with_include_metadata(self, resource_group, location, storag self.assertEqual(blobs[1].content_settings.content_language, 'spanish') self.assertEqual(blobs[1].content_settings.content_disposition, 'inline') + @GlobalStorageAccountPreparer() + def test_list_blobs_include_deletedwithversion(self, resource_group, location, storage_account, storage_account_key): + bsc = BlobServiceClient(self.account_url(storage_account, "blob"), storage_account_key) + # pytest.skip("Waiting on metadata XML fix in msrest") + container = self._create_container(bsc) + data = b'hello world' + content_settings = ContentSettings( + content_language='spanish', + content_disposition='inline') + blob1 = container.get_blob_client('blob1') + resp = blob1.upload_blob(data, overwrite=True, content_settings=content_settings, metadata={'number': '1', 'name': 'bob'}) + version_id_1 = resp['version_id'] + blob1.upload_blob(b"abc", overwrite=True) + root_content = b"cde" + root_version_id = blob1.upload_blob(root_content, overwrite=True)['version_id'] + blob1.delete_blob() + + container.get_blob_client('blob2').upload_blob(data, overwrite=True, content_settings=content_settings, metadata={'number': '2', 'name': 'car'}) + container.get_blob_client('blob3').upload_blob(data, overwrite=True, content_settings=content_settings, metadata={'number': '2', 'name': 'car'}) + + # Act + blobs =list(container.list_blobs(include=["deletedwithversions"])) + downloaded_root_content = blob1.download_blob(version_id=root_version_id).readall() + downloaded_original_content = blob1.download_blob(version_id=version_id_1).readall() + + # Assert + self.assertEqual(blobs[0].name, 'blob1') + self.assertTrue(blobs[0].has_versions_only) + self.assertEqual(root_content, downloaded_root_content) + self.assertEqual(data, downloaded_original_content) + self.assertEqual(blobs[1].name, 'blob2') + self.assertFalse(blobs[1].has_versions_only) + self.assertEqual(blobs[2].name, 'blob3') + self.assertFalse(blobs[2].has_versions_only) + @GlobalStorageAccountPreparer() def test_list_blobs_with_include_uncommittedblobs(self, resource_group, location, storage_account, storage_account_key): bsc = BlobServiceClient(self.account_url(storage_account, "blob"), storage_account_key) 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 c6d60e99ddd9..5e71216390c3 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_container_async.py @@ -1140,6 +1140,46 @@ async def test_list_blobs_with_include_metadata(self, resource_group, location, self.assertEqual(blobs[1].metadata['number'], '2') self.assertEqual(blobs[1].metadata['name'], 'car') + @GlobalStorageAccountPreparer() + async def test_list_blobs_include_deletedwithversion_async(self, resource_group, location, storage_account, storage_account_key): + bsc = BlobServiceClient(self.account_url(storage_account, "blob"), storage_account_key) + # pytest.skip("Waiting on metadata XML fix in msrest") + container = await self._create_container(bsc) + data = b'hello world' + content_settings = ContentSettings( + content_language='spanish', + content_disposition='inline') + blob1 = container.get_blob_client('blob1') + resp = await blob1.upload_blob(data, overwrite=True, content_settings=content_settings, metadata={'number': '1', 'name': 'bob'}) + version_id_1 = resp['version_id'] + await blob1.upload_blob(b"abc", overwrite=True) + root_content = b"cde" + root_version_id = (await blob1.upload_blob(root_content, overwrite=True))['version_id'] + # this will delete the root blob, while you can still access it through versioning + await blob1.delete_blob() + + await container.get_blob_client('blob2').upload_blob(data, overwrite=True, content_settings=content_settings, metadata={'number': '2', 'name': 'car'}) + await container.get_blob_client('blob3').upload_blob(data, overwrite=True, content_settings=content_settings, metadata={'number': '2', 'name': 'car'}) + + # Act + blobs = list() + + # include deletedwithversions will give you all alive root blobs and the the deleted root blobs when versioning is on. + async for blob in container.list_blobs(include=["deletedwithversions"]): + blobs.append(blob) + downloaded_root_content = await (await blob1.download_blob(version_id=root_version_id)).readall() + downloaded_original_content = await (await blob1.download_blob(version_id=version_id_1)).readall() + + # Assert + self.assertEqual(blobs[0].name, 'blob1') + self.assertTrue(blobs[0].has_versions_only) + self.assertEqual(root_content, downloaded_root_content) + self.assertEqual(data, downloaded_original_content) + self.assertEqual(blobs[1].name, 'blob2') + self.assertFalse(blobs[1].has_versions_only) + self.assertEqual(blobs[2].name, 'blob3') + self.assertFalse(blobs[2].has_versions_only) + @GlobalStorageAccountPreparer() @AsyncStorageTestCase.await_prepared_test async def test_list_blobs_with_include_uncommittedblobs(self, resource_group, location, storage_account, storage_account_key):