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 f3d2d16564a3..153b9b0751e7 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 @@ -1091,10 +1091,10 @@ def exists(self, **kwargs): Returns True if a blob exists with the defined parameters, and returns False otherwise. - :param str version_id: + :kwarg str version_id: The version id parameter is an opaque DateTime value that, when present, specifies the version of the blob to check if it exists. - :param int timeout: + :kwarg int timeout: The timeout parameter is expressed in seconds. :returns: boolean """ 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 8788d14b704a..f84d5153dc03 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 @@ -21,7 +21,7 @@ import six from azure.core import MatchConditions -from azure.core.exceptions import HttpResponseError +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError from azure.core.paging import ItemPaged from azure.core.tracing.decorator import distributed_trace from azure.core.pipeline import Pipeline @@ -459,6 +459,25 @@ def get_container_properties(self, **kwargs): response.name = self.container_name return response # type: ignore + @distributed_trace + def exists(self, **kwargs): + # type: (**Any) -> bool + """ + Returns True if a container exists and returns False otherwise. + + :kwarg int timeout: + The timeout parameter is expressed in seconds. + :returns: boolean + """ + try: + self._client.container.get_properties(**kwargs) + return True + except HttpResponseError as error: + try: + process_storage_error(error) + except ResourceNotFoundError: + return False + @distributed_trace def set_container_metadata( # type: ignore self, metadata=None, # type: Optional[Dict[str, str]] diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/aio/_blob_client_async.py b/sdk/storage/azure-storage-blob/azure/storage/blob/aio/_blob_client_async.py index 1e1ae551339f..54a4e488b162 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/aio/_blob_client_async.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/aio/_blob_client_async.py @@ -569,10 +569,10 @@ async def exists(self, **kwargs): Returns True if a blob exists with the defined parameters, and returns False otherwise. - :param str version_id: + :kwarg str version_id: The version id parameter is an opaque DateTime value that, when present, specifies the version of the blob to check if it exists. - :param int timeout: + :kwarg int timeout: The timeout parameter is expressed in seconds. :returns: boolean """ 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 e26fe2388539..aa22b976a394 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 @@ -11,7 +11,7 @@ TYPE_CHECKING ) -from azure.core.exceptions import HttpResponseError +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError from azure.core.tracing.decorator import distributed_trace from azure.core.tracing.decorator_async import distributed_trace_async from azure.core.async_paging import AsyncItemPaged @@ -335,6 +335,25 @@ async def get_container_properties(self, **kwargs): response.name = self.container_name return response # type: ignore + @distributed_trace_async + async def exists(self, **kwargs): + # type: (**Any) -> bool + """ + Returns True if a container exists and returns False otherwise. + + :kwarg int timeout: + The timeout parameter is expressed in seconds. + :returns: boolean + """ + try: + await self._client.container.get_properties(**kwargs) + return True + except HttpResponseError as error: + try: + process_storage_error(error) + except ResourceNotFoundError: + return False + @distributed_trace_async async def set_container_metadata( # type: ignore self, metadata=None, # type: Optional[Dict[str, str]] diff --git a/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_container_exists.yaml b/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_container_exists.yaml new file mode 100644 index 000000000000..29f7ea651b2d --- /dev/null +++ b/sdk/storage/azure-storage-blob/tests/recordings/test_container.test_container_exists.yaml @@ -0,0 +1,130 @@ +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.7.2 Python/3.8.5 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Sun, 24 Jan 2021 23:07:30 GMT + x-ms-version: + - '2020-04-08' + method: PUT + uri: https://storagename.blob.core.windows.net/container112fe0ef2?restype=container + response: + body: + string: "\uFEFFContainerAlreadyExistsThe + specified container already exists.\nRequestId:34e48888-401e-009f-08a5-f21ff6000000\nTime:2021-01-24T23:07:30.9942715Z" + headers: + content-length: + - '230' + content-type: + - application/xml + date: + - Sun, 24 Jan 2021 23:07:30 GMT + server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-error-code: + - ContainerAlreadyExists + x-ms-version: + - '2020-04-08' + status: + code: 409 + message: The specified container already exists. +- request: + body: null + headers: + Accept: + - application/xml + Accept-Encoding: + - gzip, deflate + Connection: + - keep-alive + User-Agent: + - azsdk-python-storage-blob/12.7.2 Python/3.8.5 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Sun, 24 Jan 2021 23:07:31 GMT + x-ms-version: + - '2020-04-08' + method: GET + uri: https://storagename.blob.core.windows.net/container112fe0ef2?restype=container + response: + body: + string: '' + headers: + content-length: + - '0' + date: + - Sun, 24 Jan 2021 23:07:31 GMT + etag: + - '"0x8D8C0BA190EF0A2"' + last-modified: + - Sun, 24 Jan 2021 22:47:58 GMT + server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + vary: + - Origin + x-ms-default-encryption-scope: + - $account-encryption-key + x-ms-deny-encryption-scope-override: + - 'false' + x-ms-has-immutability-policy: + - 'false' + x-ms-has-legal-hold: + - 'false' + x-ms-lease-state: + - available + x-ms-lease-status: + - unlocked + x-ms-version: + - '2020-04-08' + 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.7.2 Python/3.8.5 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Sun, 24 Jan 2021 23:07:31 GMT + x-ms-version: + - '2020-04-08' + method: GET + uri: https://storagename.blob.core.windows.net/container212fe0ef2?restype=container + response: + body: + string: "\uFEFFContainerNotFoundThe + specified container does not exist.\nRequestId:34e488e9-401e-009f-63a5-f21ff6000000\nTime:2021-01-24T23:07:31.1273672Z" + headers: + content-length: + - '225' + content-type: + - application/xml + date: + - Sun, 24 Jan 2021 23:07:31 GMT + server: + - Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + vary: + - Origin + x-ms-error-code: + - ContainerNotFound + x-ms-version: + - '2020-04-08' + status: + code: 404 + message: The specified container does not exist. +version: 1 diff --git a/sdk/storage/azure-storage-blob/tests/recordings/test_container_async.test_container_exists.yaml b/sdk/storage/azure-storage-blob/tests/recordings/test_container_async.test_container_exists.yaml new file mode 100644 index 000000000000..a4d34236af68 --- /dev/null +++ b/sdk/storage/azure-storage-blob/tests/recordings/test_container_async.test_container_exists.yaml @@ -0,0 +1,92 @@ +interactions: +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-blob/12.7.2 Python/3.8.5 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Sun, 24 Jan 2021 23:08:38 GMT + x-ms-version: + - '2020-04-08' + method: PUT + uri: https://storagename.blob.core.windows.net/container175a3116f?restype=container + response: + body: + string: '' + headers: + content-length: '0' + date: Sun, 24 Jan 2021 23:08:37 GMT + etag: '"0x8D8C0BCFBA744BA"' + last-modified: Sun, 24 Jan 2021 23:08:38 GMT + server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + x-ms-version: '2020-04-08' + status: + code: 201 + message: Created + url: https://emilydevtest.blob.core.windows.net/container175a3116f?restype=container +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-blob/12.7.2 Python/3.8.5 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Sun, 24 Jan 2021 23:08:38 GMT + x-ms-version: + - '2020-04-08' + method: GET + uri: https://storagename.blob.core.windows.net/container175a3116f?restype=container + response: + body: + string: '' + headers: + content-length: '0' + date: Sun, 24 Jan 2021 23:08:37 GMT + etag: '"0x8D8C0BCFBA744BA"' + last-modified: Sun, 24 Jan 2021 23:08:38 GMT + server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + vary: Origin + x-ms-default-encryption-scope: $account-encryption-key + x-ms-deny-encryption-scope-override: 'false' + x-ms-has-immutability-policy: 'false' + x-ms-has-legal-hold: 'false' + x-ms-lease-state: available + x-ms-lease-status: unlocked + x-ms-version: '2020-04-08' + status: + code: 200 + message: OK + url: https://emilydevtest.blob.core.windows.net/container175a3116f?restype=container +- request: + body: null + headers: + Accept: + - application/xml + User-Agent: + - azsdk-python-storage-blob/12.7.2 Python/3.8.5 (Windows-10-10.0.19041-SP0) + x-ms-date: + - Sun, 24 Jan 2021 23:08:38 GMT + x-ms-version: + - '2020-04-08' + method: GET + uri: https://storagename.blob.core.windows.net/container275a3116f?restype=container + response: + body: + string: "\uFEFFContainerNotFoundThe + specified container does not exist.\nRequestId:f0e7bd23-001e-00b1-54a5-f24de1000000\nTime:2021-01-24T23:08:38.1833494Z" + headers: + content-length: '225' + content-type: application/xml + date: Sun, 24 Jan 2021 23:08:37 GMT + server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0 + vary: Origin + x-ms-error-code: ContainerNotFound + x-ms-version: '2020-04-08' + status: + code: 404 + message: The specified container does not exist. + url: https://emilydevtest.blob.core.windows.net/container275a3116f?restype=container +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 ff2c33347c96..9649c8dab266 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container.py +++ b/sdk/storage/azure-storage-blob/tests/test_container.py @@ -311,6 +311,17 @@ def test_get_container_metadata_with_lease_id(self, resource_group, location, st # Assert self.assertDictEqual(md, metadata) + @GlobalStorageAccountPreparer() + def test_container_exists(self, resource_group, location, storage_account, storage_account_key): + bsc = BlobServiceClient(self.account_url(storage_account, "blob"), storage_account_key) + + container1 = self._create_container(bsc, prefix="container1") + container2_name = self._get_container_reference(prefix="container2") + container2 = bsc.get_container_client(container2_name) + + self.assertTrue(container1.exists()) + self.assertFalse(container2.exists()) + @GlobalStorageAccountPreparer() def test_get_container_properties(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 9c280615e91f..2bcfb32da4b5 100644 --- a/sdk/storage/azure-storage-blob/tests/test_container_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_container_async.py @@ -379,10 +379,24 @@ async def test_get_container_metadata_with_lease_id(self, resource_group, locati # Assert self.assertDictEqual(md, metadata) + @GlobalStorageAccountPreparer() + @AsyncStorageTestCase.await_prepared_test + async def test_container_exists(self, resource_group, location, storage_account, storage_account_key): + bsc = BlobServiceClient(self.account_url( + storage_account, "blob"), storage_account_key, transport=AiohttpTestTransport()) + + container1 = await self._create_container(bsc, prefix="container1") + container2_name = self._get_container_reference(prefix="container2") + container2 = bsc.get_container_client(container2_name) + + self.assertTrue(await container1.exists()) + self.assertFalse(await container2.exists()) + @GlobalStorageAccountPreparer() @AsyncStorageTestCase.await_prepared_test async def test_get_container_properties(self, resource_group, location, storage_account, storage_account_key): - bsc = BlobServiceClient(self.account_url(storage_account, "blob"), storage_account_key, transport=AiohttpTestTransport()) + bsc = BlobServiceClient( + self.account_url(storage_account, "blob"), storage_account_key, transport=AiohttpTestTransport()) metadata = {'hello': 'world', 'number': '42'} container = await self._create_container(bsc) await container.set_container_metadata(metadata)