diff --git a/sdk/storage/azure-storage-blob/assets.json b/sdk/storage/azure-storage-blob/assets.json index c7ffdc341154..0ed403784c2a 100644 --- a/sdk/storage/azure-storage-blob/assets.json +++ b/sdk/storage/azure-storage-blob/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "python", "TagPrefix": "python/storage/azure-storage-blob", - "Tag": "python/storage/azure-storage-blob_ba57356b0e" + "Tag": "python/storage/azure-storage-blob_863b753fbb" } diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/_patch.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/_patch.py index f99e77fef986..17dbc073e01b 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/_patch.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/_patch.py @@ -25,6 +25,7 @@ # # -------------------------------------------------------------------------- + # This file is used for handwritten extensions to the generated code. Example: # https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/customize_code/how-to-patch-sdk-code.md def patch_sdk(): diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/_patch.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/_patch.py index f99e77fef986..17dbc073e01b 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/_patch.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/_patch.py @@ -25,6 +25,7 @@ # # -------------------------------------------------------------------------- + # This file is used for handwritten extensions to the generated code. Example: # https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/customize_code/how-to-patch-sdk-code.md def patch_sdk(): diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_append_blob_operations.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_append_blob_operations.py index 23e5744c8db7..2840b96ee011 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_append_blob_operations.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_append_blob_operations.py @@ -7,7 +7,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- import datetime -from typing import Any, Callable, Dict, IO, Literal, Optional, TypeVar, Union +import sys +from typing import Any, Callable, Dict, IO, Literal, Optional, Type, TypeVar, Union from azure.core.exceptions import ( ClientAuthenticationError, @@ -32,6 +33,10 @@ build_seal_request, ) +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] @@ -119,7 +124,7 @@ async def create( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -295,7 +300,7 @@ async def append_block( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -484,7 +489,7 @@ async def append_block_from_url( # pylint: disable=inconsistent-return-statemen :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -646,7 +651,7 @@ async def seal( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_blob_operations.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_blob_operations.py index 910ebcb2358e..f71ffebc37b5 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_blob_operations.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_blob_operations.py @@ -7,7 +7,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- import datetime -from typing import Any, AsyncIterator, Callable, Dict, Literal, Optional, TypeVar, Union +import sys +from typing import Any, AsyncIterator, Callable, Dict, Literal, Optional, Type, TypeVar, Union from azure.core.exceptions import ( ClientAuthenticationError, @@ -52,6 +53,10 @@ build_undelete_request, ) +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] @@ -132,7 +137,7 @@ async def download( :rtype: AsyncIterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -419,7 +424,7 @@ async def get_properties( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -640,7 +645,7 @@ async def delete( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -731,7 +736,7 @@ async def undelete( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -809,7 +814,7 @@ async def set_expiry( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -893,7 +898,7 @@ async def set_http_headers( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1020,7 +1025,7 @@ async def set_immutability_policy( # pylint: disable=inconsistent-return-statem :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1101,7 +1106,7 @@ async def delete_immutability_policy( # pylint: disable=inconsistent-return-sta :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1171,7 +1176,7 @@ async def set_legal_hold( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1266,7 +1271,7 @@ async def set_metadata( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1399,7 +1404,7 @@ async def acquire_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1501,7 +1506,7 @@ async def release_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1601,7 +1606,7 @@ async def renew_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1707,7 +1712,7 @@ async def change_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1815,7 +1820,7 @@ async def break_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1930,7 +1935,7 @@ async def create_snapshot( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2097,7 +2102,7 @@ async def start_copy_from_url( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2279,7 +2284,7 @@ async def copy_from_url( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2420,7 +2425,7 @@ async def abort_copy_from_url( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2532,7 +2537,7 @@ async def set_tier( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2620,7 +2625,7 @@ async def get_account_info( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2716,7 +2721,7 @@ async def query( :rtype: AsyncIterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2962,7 +2967,7 @@ async def get_tags( :rtype: ~azure.storage.blob.models.BlobTags :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -3070,7 +3075,7 @@ async def set_tags( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_block_blob_operations.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_block_blob_operations.py index 6237bc20dc04..5123996799f5 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_block_blob_operations.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_block_blob_operations.py @@ -7,7 +7,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- import datetime -from typing import Any, Callable, Dict, IO, Literal, Optional, TypeVar, Union +import sys +from typing import Any, Callable, Dict, IO, Literal, Optional, Type, TypeVar, Union from azure.core.exceptions import ( ClientAuthenticationError, @@ -34,6 +35,10 @@ build_upload_request, ) +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] @@ -141,7 +146,7 @@ async def upload( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -363,7 +368,7 @@ async def put_blob_from_url( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -555,7 +560,7 @@ async def stage_block( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -706,7 +711,7 @@ async def stage_block_from_url( # pylint: disable=inconsistent-return-statement :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -890,7 +895,7 @@ async def commit_block_list( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1062,7 +1067,7 @@ async def get_block_list( :rtype: ~azure.storage.blob.models.BlockList :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_container_operations.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_container_operations.py index 8772e786345a..9a5197df8829 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_container_operations.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_container_operations.py @@ -6,7 +6,8 @@ # Code generated by Microsoft (R) AutoRest Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from typing import Any, AsyncIterator, Callable, Dict, IO, List, Literal, Optional, TypeVar, Union +import sys +from typing import Any, AsyncIterator, Callable, Dict, IO, List, Literal, Optional, Type, TypeVar, Union from azure.core.exceptions import ( ClientAuthenticationError, @@ -45,6 +46,10 @@ build_submit_batch_request, ) +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] @@ -107,7 +112,7 @@ async def create( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -194,7 +199,7 @@ async def get_properties( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -299,7 +304,7 @@ async def delete( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -397,7 +402,7 @@ async def set_metadata( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -486,7 +491,7 @@ async def get_access_policy( :rtype: list[~azure.storage.blob.models.SignedIdentifier] :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -587,7 +592,7 @@ async def set_access_policy( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -693,7 +698,7 @@ async def restore( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -776,7 +781,7 @@ async def rename( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -857,7 +862,7 @@ async def submit_batch( :rtype: AsyncIterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -964,7 +969,7 @@ async def filter_blobs( :rtype: ~azure.storage.blob.models.FilterBlobSegment :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1059,7 +1064,7 @@ async def acquire_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1154,7 +1159,7 @@ async def release_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1247,7 +1252,7 @@ async def renew_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1347,7 +1352,7 @@ async def break_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1446,7 +1451,7 @@ async def change_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1558,7 +1563,7 @@ async def list_blob_flat_segment( :rtype: ~azure.storage.blob.models.ListBlobsFlatSegmentResponse :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1670,7 +1675,7 @@ async def list_blob_hierarchy_segment( :rtype: ~azure.storage.blob.models.ListBlobsHierarchySegmentResponse :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1750,7 +1755,7 @@ async def get_account_info( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_page_blob_operations.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_page_blob_operations.py index 854d58017352..45d5c64de5fb 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_page_blob_operations.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_page_blob_operations.py @@ -7,7 +7,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- import datetime -from typing import Any, Callable, Dict, IO, Literal, Optional, TypeVar, Union +import sys +from typing import Any, Callable, Dict, IO, Literal, Optional, Type, TypeVar, Union from azure.core.exceptions import ( ClientAuthenticationError, @@ -37,6 +38,10 @@ build_upload_pages_request, ) +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] @@ -137,7 +142,7 @@ async def create( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -317,7 +322,7 @@ async def upload_pages( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -485,7 +490,7 @@ async def clear_pages( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -663,7 +668,7 @@ async def upload_pages_from_url( # pylint: disable=inconsistent-return-statemen :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -851,7 +856,7 @@ async def get_page_ranges( :rtype: ~azure.storage.blob.models.PageList :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1003,7 +1008,7 @@ async def get_page_ranges_diff( :rtype: ~azure.storage.blob.models.PageList :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1126,7 +1131,7 @@ async def resize( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1255,7 +1260,7 @@ async def update_sequence_number( # pylint: disable=inconsistent-return-stateme :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1367,7 +1372,7 @@ async def copy_incremental( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_service_operations.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_service_operations.py index eeb45644cdf2..7a3c62fec53d 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_service_operations.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/aio/operations/_service_operations.py @@ -6,7 +6,8 @@ # Code generated by Microsoft (R) AutoRest Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from typing import Any, AsyncIterator, Callable, Dict, IO, List, Literal, Optional, TypeVar, Union +import sys +from typing import Any, AsyncIterator, Callable, Dict, IO, List, Literal, Optional, Type, TypeVar, Union from azure.core.exceptions import ( ClientAuthenticationError, @@ -35,6 +36,10 @@ build_submit_batch_request, ) +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] @@ -84,7 +89,7 @@ async def set_properties( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -159,7 +164,7 @@ async def get_properties( :rtype: ~azure.storage.blob.models.StorageServiceProperties :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -234,7 +239,7 @@ async def get_statistics( :rtype: ~azure.storage.blob.models.StorageServiceStats :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -336,7 +341,7 @@ async def list_containers_segment( :rtype: ~azure.storage.blob.models.ListContainersSegmentResponse :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -418,7 +423,7 @@ async def get_user_delegation_key( :rtype: ~azure.storage.blob.models.UserDelegationKey :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -497,7 +502,7 @@ async def get_account_info( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -579,7 +584,7 @@ async def submit_batch( :rtype: AsyncIterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -685,7 +690,7 @@ async def filter_blobs( :rtype: ~azure.storage.blob.models.FilterBlobSegment :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, 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 cd88cb20487f..4676b0eb1be4 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 @@ -2580,19 +2580,45 @@ class StorageError(_serialization.Model): :ivar message: :vartype message: str + :ivar copy_source_status_code: + :vartype copy_source_status_code: int + :ivar copy_source_error_code: + :vartype copy_source_error_code: str + :ivar copy_source_error_message: + :vartype copy_source_error_message: str """ _attribute_map = { "message": {"key": "Message", "type": "str"}, + "copy_source_status_code": {"key": "CopySourceStatusCode", "type": "int"}, + "copy_source_error_code": {"key": "CopySourceErrorCode", "type": "str"}, + "copy_source_error_message": {"key": "CopySourceErrorMessage", "type": "str"}, } - def __init__(self, *, message: Optional[str] = None, **kwargs: Any) -> None: + def __init__( + self, + *, + message: Optional[str] = None, + copy_source_status_code: Optional[int] = None, + copy_source_error_code: Optional[str] = None, + copy_source_error_message: Optional[str] = None, + **kwargs: Any + ) -> None: """ :keyword message: :paramtype message: str + :keyword copy_source_status_code: + :paramtype copy_source_status_code: int + :keyword copy_source_error_code: + :paramtype copy_source_error_code: str + :keyword copy_source_error_message: + :paramtype copy_source_error_message: str """ super().__init__(**kwargs) self.message = message + self.copy_source_status_code = copy_source_status_code + self.copy_source_error_code = copy_source_error_code + self.copy_source_error_message = copy_source_error_message class StorageServiceProperties(_serialization.Model): diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_append_blob_operations.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_append_blob_operations.py index c412a42591ea..f950ba4053bc 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_append_blob_operations.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_append_blob_operations.py @@ -7,7 +7,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- import datetime -from typing import Any, Callable, Dict, IO, Literal, Optional, TypeVar, Union +import sys +from typing import Any, Callable, Dict, IO, Literal, Optional, Type, TypeVar, Union from azure.core.exceptions import ( ClientAuthenticationError, @@ -27,6 +28,10 @@ from .._serialization import Serializer from .._vendor import _convert_request +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -489,7 +494,7 @@ def create( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -665,7 +670,7 @@ def append_block( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -854,7 +859,7 @@ def append_block_from_url( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1016,7 +1021,7 @@ def seal( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_blob_operations.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_blob_operations.py index b3eba6f4a8c1..385821f836a3 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_blob_operations.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_blob_operations.py @@ -7,7 +7,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- import datetime -from typing import Any, Callable, Dict, Iterator, Literal, Optional, TypeVar, Union +import sys +from typing import Any, Callable, Dict, Iterator, Literal, Optional, Type, TypeVar, Union from azure.core.exceptions import ( ClientAuthenticationError, @@ -27,6 +28,10 @@ from .._serialization import Serializer from .._vendor import _convert_request +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -1539,7 +1544,7 @@ def download( :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1826,7 +1831,7 @@ def get_properties( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2047,7 +2052,7 @@ def delete( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2138,7 +2143,7 @@ def undelete( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2216,7 +2221,7 @@ def set_expiry( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2300,7 +2305,7 @@ def set_http_headers( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2427,7 +2432,7 @@ def set_immutability_policy( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2508,7 +2513,7 @@ def delete_immutability_policy( # pylint: disable=inconsistent-return-statement :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2578,7 +2583,7 @@ def set_legal_hold( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2673,7 +2678,7 @@ def set_metadata( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2806,7 +2811,7 @@ def acquire_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2908,7 +2913,7 @@ def release_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -3008,7 +3013,7 @@ def renew_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -3114,7 +3119,7 @@ def change_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -3222,7 +3227,7 @@ def break_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -3337,7 +3342,7 @@ def create_snapshot( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -3504,7 +3509,7 @@ def start_copy_from_url( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -3686,7 +3691,7 @@ def copy_from_url( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -3827,7 +3832,7 @@ def abort_copy_from_url( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -3939,7 +3944,7 @@ def set_tier( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -4027,7 +4032,7 @@ def get_account_info( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -4123,7 +4128,7 @@ def query( :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -4369,7 +4374,7 @@ def get_tags( :rtype: ~azure.storage.blob.models.BlobTags :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -4477,7 +4482,7 @@ def set_tags( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_block_blob_operations.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_block_blob_operations.py index 35164fd08cb6..0a3083b16a7b 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_block_blob_operations.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_block_blob_operations.py @@ -7,7 +7,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- import datetime -from typing import Any, Callable, Dict, IO, Literal, Optional, TypeVar, Union +import sys +from typing import Any, Callable, Dict, IO, Literal, Optional, Type, TypeVar, Union from azure.core.exceptions import ( ClientAuthenticationError, @@ -27,6 +28,10 @@ from .._serialization import Serializer from .._vendor import _convert_request +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -749,7 +754,7 @@ def upload( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -971,7 +976,7 @@ def put_blob_from_url( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1163,7 +1168,7 @@ def stage_block( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1314,7 +1319,7 @@ def stage_block_from_url( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1498,7 +1503,7 @@ def commit_block_list( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1670,7 +1675,7 @@ def get_block_list( :rtype: ~azure.storage.blob.models.BlockList :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_container_operations.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_container_operations.py index b14eabb97e42..37fe1f75556b 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_container_operations.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_container_operations.py @@ -7,7 +7,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- import datetime -from typing import Any, Callable, Dict, IO, Iterator, List, Literal, Optional, TypeVar, Union +import sys +from typing import Any, Callable, Dict, IO, Iterator, List, Literal, Optional, Type, TypeVar, Union from azure.core.exceptions import ( ClientAuthenticationError, @@ -27,6 +28,10 @@ from .._serialization import Serializer from .._vendor import _convert_request +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -938,7 +943,7 @@ def create( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1025,7 +1030,7 @@ def get_properties( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1130,7 +1135,7 @@ def delete( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1228,7 +1233,7 @@ def set_metadata( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1317,7 +1322,7 @@ def get_access_policy( :rtype: list[~azure.storage.blob.models.SignedIdentifier] :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1418,7 +1423,7 @@ def set_access_policy( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1524,7 +1529,7 @@ def restore( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1607,7 +1612,7 @@ def rename( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1688,7 +1693,7 @@ def submit_batch( :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1795,7 +1800,7 @@ def filter_blobs( :rtype: ~azure.storage.blob.models.FilterBlobSegment :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1890,7 +1895,7 @@ def acquire_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1985,7 +1990,7 @@ def release_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2078,7 +2083,7 @@ def renew_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2178,7 +2183,7 @@ def break_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2277,7 +2282,7 @@ def change_lease( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2389,7 +2394,7 @@ def list_blob_flat_segment( :rtype: ~azure.storage.blob.models.ListBlobsFlatSegmentResponse :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2501,7 +2506,7 @@ def list_blob_hierarchy_segment( :rtype: ~azure.storage.blob.models.ListBlobsHierarchySegmentResponse :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2581,7 +2586,7 @@ def get_account_info( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_page_blob_operations.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_page_blob_operations.py index 63d50d3331a3..e388063fc7fa 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_page_blob_operations.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_page_blob_operations.py @@ -7,7 +7,8 @@ # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- import datetime -from typing import Any, Callable, Dict, IO, Literal, Optional, TypeVar, Union +import sys +from typing import Any, Callable, Dict, IO, Literal, Optional, Type, TypeVar, Union from azure.core.exceptions import ( ClientAuthenticationError, @@ -27,6 +28,10 @@ from .._serialization import Serializer from .._vendor import _convert_request +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -889,7 +894,7 @@ def create( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1069,7 +1074,7 @@ def upload_pages( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1237,7 +1242,7 @@ def clear_pages( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1415,7 +1420,7 @@ def upload_pages_from_url( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1603,7 +1608,7 @@ def get_page_ranges( :rtype: ~azure.storage.blob.models.PageList :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1755,7 +1760,7 @@ def get_page_ranges_diff( :rtype: ~azure.storage.blob.models.PageList :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -1878,7 +1883,7 @@ def resize( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2007,7 +2012,7 @@ def update_sequence_number( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -2119,7 +2124,7 @@ def copy_incremental( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_service_operations.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_service_operations.py index 9f2529836450..0d1bc1509661 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_service_operations.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_generated/operations/_service_operations.py @@ -6,7 +6,8 @@ # Code generated by Microsoft (R) AutoRest Code Generator. # Changes may cause incorrect behavior and will be lost if the code is regenerated. # -------------------------------------------------------------------------- -from typing import Any, Callable, Dict, IO, Iterator, List, Literal, Optional, TypeVar, Union +import sys +from typing import Any, Callable, Dict, IO, Iterator, List, Literal, Optional, Type, TypeVar, Union from azure.core.exceptions import ( ClientAuthenticationError, @@ -26,6 +27,10 @@ from .._serialization import Serializer from .._vendor import _convert_request +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore # pylint: disable=ungrouped-imports T = TypeVar("T") ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] @@ -392,7 +397,7 @@ def set_properties( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -467,7 +472,7 @@ def get_properties( :rtype: ~azure.storage.blob.models.StorageServiceProperties :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -542,7 +547,7 @@ def get_statistics( :rtype: ~azure.storage.blob.models.StorageServiceStats :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -644,7 +649,7 @@ def list_containers_segment( :rtype: ~azure.storage.blob.models.ListContainersSegmentResponse :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -726,7 +731,7 @@ def get_user_delegation_key( :rtype: ~azure.storage.blob.models.UserDelegationKey :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -805,7 +810,7 @@ def get_account_info( # pylint: disable=inconsistent-return-statements :rtype: None :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -887,7 +892,7 @@ def submit_batch( :rtype: Iterator[bytes] :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, @@ -993,7 +998,7 @@ def filter_blobs( :rtype: ~azure.storage.blob.models.FilterBlobSegment :raises ~azure.core.exceptions.HttpResponseError: """ - error_map = { + error_map: MutableMapping[int, Type[HttpResponseError]] = { 401: ClientAuthenticationError, 404: ResourceNotFoundError, 409: ResourceExistsError, diff --git a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/policies.py b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/policies.py index 4596cb3d1b81..b2cd79e0b7e4 100644 --- a/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/policies.py +++ b/sdk/storage/azure-storage-blob/azure/storage/blob/_shared/policies.py @@ -33,7 +33,7 @@ from .authentication import StorageHttpChallenge from .constants import DEFAULT_OAUTH_SCOPE -from .models import LocationMode +from .models import LocationMode, StorageErrorCode try: _unicode_type = unicode # type: ignore @@ -88,6 +88,15 @@ def is_retry(response, mode): # pylint: disable=too-many-return-statements if status == 408: # Response code 408 is a timeout and should be retried. return True + if status >= 400: + error_code = response.http_response.headers.get('x-ms-copy-source-error-code') + retry_codes = [ + StorageErrorCode.OPERATION_TIMED_OUT, + StorageErrorCode.INTERNAL_ERROR, + StorageErrorCode.SERVER_BUSY + ] + if error_code in retry_codes: + return True return False if status >= 500: # Response codes above 500 with the exception of 501 Not Implemented and 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 e6b653035835..dc84c2dbfb25 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 @@ -4,7 +4,7 @@ # license information. # -------------------------------------------------------------------------- import logging -from typing import NoReturn +from typing import Dict, NoReturn, Optional from xml.etree.ElementTree import Element from azure.core.exceptions import ( @@ -81,7 +81,7 @@ def return_raw_deserialized(response, *_): return response.http_response.location_mode, response.context[ContentDecodePolicy.CONTEXT_NAME] -def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # pylint:disable=too-many-statements +def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # pylint:disable=too-many-statements, too-many-branches raise_error = HttpResponseError serialized = False if not storage_error.response or storage_error.response.status_code in [200, 204]: @@ -92,8 +92,8 @@ def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # py serialized = True error_code = storage_error.response.headers.get('x-ms-error-code') error_message = storage_error.message - additional_data = {} - error_dict = {} + additional_data: Dict[str, Optional[str]] = {} + error_dict: Dict[str, Optional[str]] = {} try: error_body = ContentDecodePolicy.deserialize_from_http_generics(storage_error.response) try: @@ -104,7 +104,7 @@ def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # py # If it is an XML response if isinstance(error_body, Element): error_dict = { - child.tag.lower(): child.text + child.tag: child.text for child in error_body } # If it is a JSON response @@ -118,9 +118,14 @@ def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # py # If we extracted from a Json or XML response # There is a chance error_dict is just a string if error_dict and isinstance(error_dict, dict): - error_code = error_dict.get('code') - error_message = error_dict.get('message') - additional_data = {k: v for k, v in error_dict.items() if k not in {'code', 'message'}} + for k, v in error_dict.items(): + k_lower = k.lower() + if k_lower == 'code': + error_code = v + elif k_lower == 'message': + error_message = v + else: + additional_data[k] = v except DecodeError: pass diff --git a/sdk/storage/azure-storage-blob/tests/test_append_blob.py b/sdk/storage/azure-storage-blob/tests/test_append_blob.py index 6b309847b672..ecfe5bba2efe 100644 --- a/sdk/storage/azure-storage-blob/tests/test_append_blob.py +++ b/sdk/storage/azure-storage-blob/tests/test_append_blob.py @@ -340,6 +340,29 @@ def test_append_block_from_url(self, **kwargs): destination_blob_client.append_block_from_url(source_blob_client.url + '?' + sas, source_length=LARGE_BLOB_SIZE) + @BlobPreparer() + @recorded_by_proxy + def test_append_blob_async_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + bsc = BlobServiceClient( + self.account_url(storage_account_name, "blob"), + credential=storage_account_key, + max_page_size=4 * 1024) + self._setup(bsc) + source_blob = self._create_blob(bsc) + dest_blob = self._create_blob(bsc) + + # Act + with pytest.raises(HttpResponseError) as e: + dest_blob.append_block_from_url(source_blob.url) + + # Assert + assert e.value.response.headers["x-ms-copy-source-status-code"] == "409" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "PublicAccessNotPermitted" + @BlobPreparer() @recorded_by_proxy def test_append_block_from_url_and_validate_content_md5(self, **kwargs): diff --git a/sdk/storage/azure-storage-blob/tests/test_append_blob_async.py b/sdk/storage/azure-storage-blob/tests/test_append_blob_async.py index 811c0cd2cda7..9ffc503069db 100644 --- a/sdk/storage/azure-storage-blob/tests/test_append_blob_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_append_blob_async.py @@ -328,6 +328,29 @@ async def test_append_block_from_url(self, **kwargs): await destination_blob_client.append_block_from_url(source_blob_client.url + '?' + sas, source_length=LARGE_BLOB_SIZE) + @BlobPreparer() + @recorded_by_proxy_async + async def test_append_blob_async_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + bsc = BlobServiceClient( + self.account_url(storage_account_name, "blob"), + credential=storage_account_key, + max_page_size=4 * 1024) + await self._setup(bsc) + source_blob = await self._create_blob(bsc) + dest_blob = await self._create_blob(bsc) + + # Act + with pytest.raises(HttpResponseError) as e: + await dest_blob.append_block_from_url(source_blob.url) + + # Assert + assert e.value.response.headers["x-ms-copy-source-status-code"] == "409" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "PublicAccessNotPermitted" + @BlobPreparer() @recorded_by_proxy_async async def test_append_block_from_url_and_validate_content_md5(self, **kwargs): diff --git a/sdk/storage/azure-storage-blob/tests/test_block_blob.py b/sdk/storage/azure-storage-blob/tests/test_block_blob.py index 0db4213f78df..60faee7b7403 100644 --- a/sdk/storage/azure-storage-blob/tests/test_block_blob.py +++ b/sdk/storage/azure-storage-blob/tests/test_block_blob.py @@ -499,6 +499,27 @@ def test_put_block(self, **kwargs): # Assert + @BlobPreparer() + @recorded_by_proxy + def test_upload_blob_from_url_sync_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + self._setup(storage_account_name, storage_account_key) + source_blob_name = "sourceblob" + source_blob = self.bsc.get_blob_client(self.container_name, source_blob_name) + target_blob_name = "targetblob" + target_blob = self.bsc.get_blob_client(self.container_name, target_blob_name) + + # Act + with pytest.raises(HttpResponseError) as e: + target_blob.upload_blob_from_url(source_blob.url) + + # Assert + assert e.value.response.headers["x-ms-copy-source-status-code"] == "409" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "PublicAccessNotPermitted" + @BlobPreparer() @recorded_by_proxy def test_put_block_with_response(self, **kwargs): @@ -624,6 +645,32 @@ def test_put_block_with_immutability_policy(self, **kwargs): return variables + @BlobPreparer() + @recorded_by_proxy + def test_stage_block_from_url_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + self._setup(storage_account_name, storage_account_key) + source_blob_name = "sourceblob" + source_blob = self.bsc.get_blob_client(self.container_name, source_blob_name) + target_blob_name = "targetblob" + target_blob = self.bsc.get_blob_client(self.container_name, target_blob_name) + split = 4 * 1024 + + # Act + with pytest.raises(HttpResponseError) as e: + target_blob.stage_block_from_url( + block_id=1, + source_url=source_blob.url, + source_offset=0, + source_length=split) + + # Assert + assert e.value.response.headers["x-ms-copy-source-status-code"] == "409" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "PublicAccessNotPermitted" + @BlobPreparer() @recorded_by_proxy def test_put_block_list_invalid_block_id(self, **kwargs): diff --git a/sdk/storage/azure-storage-blob/tests/test_block_blob_async.py b/sdk/storage/azure-storage-blob/tests/test_block_blob_async.py index 2002a7188a67..503d253bbd0e 100644 --- a/sdk/storage/azure-storage-blob/tests/test_block_blob_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_block_blob_async.py @@ -509,6 +509,27 @@ async def test_upload_blob_from_url_source_and_destination_properties(self, **kw assert new_blob_copy1_props.tag_count is None assert new_blob_copy2_props.tag_count is None + @BlobPreparer() + @recorded_by_proxy_async + async def test_upload_blob_from_url_sync_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + await self._setup(storage_account_name, storage_account_key) + source_blob_name = "sourceblob" + source_blob = self.bsc.get_blob_client(self.container_name, source_blob_name) + target_blob_name = "targetblob" + target_blob = self.bsc.get_blob_client(self.container_name, target_blob_name) + + # Act + with pytest.raises(HttpResponseError) as e: + await target_blob.upload_blob_from_url(source_blob.url) + + # Assert + assert e.value.response.headers["x-ms-copy-source-status-code"] == "409" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "PublicAccessNotPermitted" + @BlobPreparer() @recorded_by_proxy_async async def test_put_block(self, **kwargs): @@ -576,6 +597,32 @@ async def test_put_block_from_url_and_commit(self, **kwargs): assert len(uncommitted) == 0 assert len(committed) == 2 + @BlobPreparer() + @recorded_by_proxy_async + async def test_stage_block_from_url_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + await self._setup(storage_account_name, storage_account_key) + source_blob_name = "sourceblob" + source_blob = self.bsc.get_blob_client(self.container_name, source_blob_name) + target_blob_name = "targetblob" + target_blob = self.bsc.get_blob_client(self.container_name, target_blob_name) + split = 4 * 1024 + + # Act + with pytest.raises(HttpResponseError) as e: + await target_blob.stage_block_from_url( + block_id=1, + source_url=source_blob.url, + source_offset=0, + source_length=split) + + # Assert + assert e.value.response.headers["x-ms-copy-source-status-code"] == "409" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "PublicAccessNotPermitted" + @BlobPreparer() @recorded_by_proxy_async async def test_put_block_with_response(self, **kwargs): diff --git a/sdk/storage/azure-storage-blob/tests/test_common_blob.py b/sdk/storage/azure-storage-blob/tests/test_common_blob.py index a19f8b003b78..1b504a0db53a 100644 --- a/sdk/storage/azure-storage-blob/tests/test_common_blob.py +++ b/sdk/storage/azure-storage-blob/tests/test_common_blob.py @@ -1693,6 +1693,59 @@ def test_abort_copy_blob_with_synchronous_copy_fails(self, **kwargs): # Assert assert copy_resp['copy_status'] == 'success' + @BlobPreparer() + @recorded_by_proxy + def test_copy_blob_async_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + self._setup(storage_account_name, storage_account_key) + source_blob_name = "sourceblob" + source_blob = self.bsc.get_blob_client(self.container_name, source_blob_name) + target_blob_name = "targetblob" + target_blob = self.bsc.get_blob_client(self.container_name, target_blob_name) + + sas_token = self.generate_sas( + generate_blob_sas, + source_blob.account_name, + source_blob.container_name, + source_blob.blob_name, + account_key=source_blob.credential.account_key, + permission=BlobSasPermissions(read=True), + expiry=datetime.utcnow() + timedelta(hours=1), + ) + blob = BlobClient.from_blob_url(source_blob.url, credential=sas_token) + + # Act + with pytest.raises(HttpResponseError) as e: + target_blob.start_copy_from_url(blob.url) + + # Assert + assert e.value.response.headers["x-ms-copy-source-error-code"] == "BlobNotFound" + assert e.value.response.headers["x-ms-copy-source-status-code"] == "404" + + @BlobPreparer() + @recorded_by_proxy + def test_copy_blob_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + self._setup(storage_account_name, storage_account_key) + source_blob_name = "sourceblob" + source_blob = self.bsc.get_blob_client(self.container_name, source_blob_name) + target_blob_name = "targetblob" + target_blob = self.bsc.get_blob_client(self.container_name, target_blob_name) + + # Act + with pytest.raises(HttpResponseError) as e: + target_blob.start_copy_from_url(source_blob.url, requires_sync=True) + + # Assert + assert e.value.response.headers["x-ms-copy-source-status-code"] == "409" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "PublicAccessNotPermitted" + @BlobPreparer() @recorded_by_proxy def test_snapshot_blob(self, **kwargs): diff --git a/sdk/storage/azure-storage-blob/tests/test_common_blob_async.py b/sdk/storage/azure-storage-blob/tests/test_common_blob_async.py index 9c1f4c2f0464..0434009b686a 100644 --- a/sdk/storage/azure-storage-blob/tests/test_common_blob_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_common_blob_async.py @@ -1907,6 +1907,59 @@ async def test_abort_copy_blob_with_synchronous_copy_fails(self, **kwargs): # Assert assert copy_resp['copy_status'] == 'success' + @BlobPreparer() + @recorded_by_proxy_async + async def test_copy_blob_async_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + await self._setup(storage_account_name, storage_account_key) + source_blob_name = "sourceblob" + source_blob = self.bsc.get_blob_client(self.container_name, source_blob_name) + target_blob_name = "targetblob" + target_blob = self.bsc.get_blob_client(self.container_name, target_blob_name) + + sas_token = self.generate_sas( + generate_blob_sas, + source_blob.account_name, + source_blob.container_name, + source_blob.blob_name, + account_key=source_blob.credential.account_key, + permission=BlobSasPermissions(read=True), + expiry=datetime.utcnow() + timedelta(hours=1), + ) + blob = BlobClient.from_blob_url(source_blob.url, credential=sas_token) + + # Act + with pytest.raises(HttpResponseError) as e: + await target_blob.start_copy_from_url(blob.url) + + # Assert + assert e.value.response.headers["x-ms-copy-source-error-code"] == "BlobNotFound" + assert e.value.response.headers["x-ms-copy-source-status-code"] == "404" + + @BlobPreparer() + @recorded_by_proxy_async + async def test_copy_blob_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + await self._setup(storage_account_name, storage_account_key) + source_blob_name = "sourceblob" + source_blob = self.bsc.get_blob_client(self.container_name, source_blob_name) + target_blob_name = "targetblob" + target_blob = self.bsc.get_blob_client(self.container_name, target_blob_name) + + # Act + with pytest.raises(HttpResponseError) as e: + await target_blob.start_copy_from_url(source_blob.url, requires_sync=True) + + # Assert + assert e.value.response.headers["x-ms-copy-source-status-code"] == "409" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "PublicAccessNotPermitted" + @BlobPreparer() @recorded_by_proxy_async async def test_snapshot_blob(self, **kwargs): diff --git a/sdk/storage/azure-storage-blob/tests/test_page_blob.py b/sdk/storage/azure-storage-blob/tests/test_page_blob.py index beb40b426064..b03965677a3a 100644 --- a/sdk/storage/azure-storage-blob/tests/test_page_blob.py +++ b/sdk/storage/azure-storage-blob/tests/test_page_blob.py @@ -577,6 +577,29 @@ def test_upload_pages_from_url(self, **kwargs): assert blob_properties.get('etag') == source_with_special_chars_resp.get('etag') assert blob_properties.get('last_modified') == source_with_special_chars_resp.get('last_modified') + @BlobPreparer() + @recorded_by_proxy + def test_upload_pages_from_url_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + bsc = BlobServiceClient( + self.account_url(storage_account_name, "blob"), + credential=storage_account_key, + max_page_size=4 * 1024) + self._setup(bsc) + source_blob = self._create_blob(bsc) + dest_blob = self._create_blob(bsc) + + # Act + with pytest.raises(HttpResponseError) as e: + dest_blob.upload_blob_from_url(source_blob.url) + + # Assert + assert e.value.response.headers["x-ms-copy-source-status-code"] == "409" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "PublicAccessNotPermitted" + @BlobPreparer() @recorded_by_proxy def test_upload_pages_from_url_with_oauth(self, **kwargs): diff --git a/sdk/storage/azure-storage-blob/tests/test_page_blob_async.py b/sdk/storage/azure-storage-blob/tests/test_page_blob_async.py index 27bc668bcf69..cfc831f7f55c 100644 --- a/sdk/storage/azure-storage-blob/tests/test_page_blob_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_page_blob_async.py @@ -564,6 +564,29 @@ async def test_upload_pages_from_url(self, **kwargs): assert blob_properties.get('etag') == resp.get('etag') assert blob_properties.get('last_modified') == resp.get('last_modified') + @BlobPreparer() + @recorded_by_proxy_async + async def test_upload_pages_from_url_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + bsc = BlobServiceClient( + self.account_url(storage_account_name, "blob"), + credential=storage_account_key, + max_page_size=4 * 1024) + await self._setup(bsc) + source_blob = await self._create_blob(bsc) + dest_blob = await self._create_blob(bsc) + + # Act + with pytest.raises(HttpResponseError) as e: + await dest_blob.upload_blob_from_url(source_blob.url) + + # Assert + assert e.value.response.headers["x-ms-copy-source-status-code"] == "409" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "PublicAccessNotPermitted" + @BlobPreparer() @recorded_by_proxy_async async def test_upload_pages_from_url_and_validate_content_md5(self, **kwargs): diff --git a/sdk/storage/azure-storage-blob/tests/test_retry.py b/sdk/storage/azure-storage-blob/tests/test_retry.py index 489f823d9197..c91e2365ab4c 100644 --- a/sdk/storage/azure-storage-blob/tests/test_retry.py +++ b/sdk/storage/azure-storage-blob/tests/test_retry.py @@ -21,6 +21,7 @@ LinearRetry, LocationMode ) +from azure.storage.blob._shared.models import StorageErrorCode from requests import Response from requests.exceptions import ContentDecodingError, ChunkedEncodingError, ReadTimeout @@ -550,4 +551,63 @@ def test_streaming_retry(self, **kwargs): blob.download_blob() assert iterator_mock.__next__.call_count == count[0] == 3 + @BlobPreparer() + @recorded_by_proxy + def test_retry_on_copy_source_error(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + """Test that retry on timeout, server error, server busy if surfaced from x-ms-copy-source-status-code.""" + # Arrange + container_name = self.get_resource_name('utcontainer') + retry = LinearRetry(backoff=1, retry_total=3) + retry_counter = RetryCounter() + service = self._create_storage_service( + BlobServiceClient, + storage_account_name, + storage_account_key, + retry_policy=retry) + + def response_handler(raw_response): + if retry_counter.count == 0: + raw_response.http_response.status_code = 400 + raw_response.http_response.headers['x-ms-copy-source-status-code'] = '408' + raw_response.http_response.headers['x-ms-copy-source-error-code'] = ( + StorageErrorCode.OPERATION_TIMED_OUT) + elif retry_counter.count == 1: + raw_response.http_response.status_code = 400 + raw_response.http_response.headers['x-ms-copy-source-status-code'] = '500' + raw_response.http_response.headers['x-ms-copy-source-error-code'] = StorageErrorCode.INTERNAL_ERROR + elif retry_counter.count == 2: + raw_response.http_response.status_code = 400 + raw_response.http_response.headers['x-ms-copy-source-status-code'] = '503' + raw_response.http_response.headers['x-ms-copy-source-error-code'] = StorageErrorCode.SERVER_BUSY + + def assert_exception_is_present_on_retry_context(**kwargs): + assert kwargs.get('response') is not None + if retry_counter.count == 0: + assert kwargs['response'].status_code == 400 + assert kwargs['response'].headers['x-ms-copy-source-status-code'] == '408' + assert kwargs['response'].headers['x-ms-copy-source-error-code'] == ( + StorageErrorCode.OPERATION_TIMED_OUT) + elif retry_counter.count == 1: + assert kwargs['response'].status_code == 400 + assert kwargs['response'].headers['x-ms-copy-source-status-code'] == '500' + assert kwargs['response'].headers['x-ms-copy-source-error-code'] == StorageErrorCode.INTERNAL_ERROR + elif retry_counter.count == 2: + assert kwargs['response'].status_code == 400 + assert kwargs['response'].headers['x-ms-copy-source-status-code'] == '503' + assert kwargs['response'].headers['x-ms-copy-source-error-code'] == StorageErrorCode.SERVER_BUSY + retry_counter.simple_count(retry) + + # Act + with pytest.raises(HttpResponseError): + service.create_container( + container_name, + raw_response_hook=response_handler, + retry_hook=assert_exception_is_present_on_retry_context) + + # Assert + assert retry_counter.count == 3 + # ------------------------------------------------------------------------------ diff --git a/sdk/storage/azure-storage-blob/tests/test_retry_async.py b/sdk/storage/azure-storage-blob/tests/test_retry_async.py index f19e092d6956..371bba0d4dfb 100644 --- a/sdk/storage/azure-storage-blob/tests/test_retry_async.py +++ b/sdk/storage/azure-storage-blob/tests/test_retry_async.py @@ -20,6 +20,7 @@ from azure.core.pipeline.transport import AioHttpTransport from azure.storage.blob import LocationMode from azure.storage.blob._shared.policies_async import ExponentialRetry, LinearRetry +from azure.storage.blob._shared.models import StorageErrorCode from azure.storage.blob.aio import BlobServiceClient from devtools_testutils import ResponseCallback, RetryCounter @@ -529,4 +530,63 @@ async def test_streaming_retry(self, **kwargs): await blob.download_blob() assert stream_reader_read_mock.call_count == count[0] == 4 + @BlobPreparer() + @recorded_by_proxy_async + async def test_retry_on_copy_source_error(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + """Test that retry on timeout, server error, server busy if surfaced from x-ms-copy-source-status-code.""" + # Arrange + container_name = self.get_resource_name('utcontainer') + retry = LinearRetry(backoff=1, retry_total=3) + retry_counter = RetryCounter() + service = self._create_storage_service( + BlobServiceClient, + storage_account_name, + storage_account_key, + retry_policy=retry) + + def response_handler(raw_response): + if retry_counter.count == 0: + raw_response.http_response.status_code = 400 + raw_response.http_response.headers['x-ms-copy-source-status-code'] = '408' + raw_response.http_response.headers['x-ms-copy-source-error-code'] = ( + StorageErrorCode.OPERATION_TIMED_OUT) + elif retry_counter.count == 1: + raw_response.http_response.status_code = 400 + raw_response.http_response.headers['x-ms-copy-source-status-code'] = '500' + raw_response.http_response.headers['x-ms-copy-source-error-code'] = StorageErrorCode.INTERNAL_ERROR + elif retry_counter.count == 2: + raw_response.http_response.status_code = 400 + raw_response.http_response.headers['x-ms-copy-source-status-code'] = '503' + raw_response.http_response.headers['x-ms-copy-source-error-code'] = StorageErrorCode.SERVER_BUSY + + def assert_exception_is_present_on_retry_context(**kwargs): + assert kwargs.get('response') is not None + if retry_counter.count == 0: + assert kwargs['response'].status_code == 400 + assert kwargs['response'].headers['x-ms-copy-source-status-code'] == '408' + assert kwargs['response'].headers['x-ms-copy-source-error-code'] == ( + StorageErrorCode.OPERATION_TIMED_OUT) + elif retry_counter.count == 1: + assert kwargs['response'].status_code == 400 + assert kwargs['response'].headers['x-ms-copy-source-status-code'] == '500' + assert kwargs['response'].headers['x-ms-copy-source-error-code'] == StorageErrorCode.INTERNAL_ERROR + elif retry_counter.count == 2: + assert kwargs['response'].status_code == 400 + assert kwargs['response'].headers['x-ms-copy-source-status-code'] == '503' + assert kwargs['response'].headers['x-ms-copy-source-error-code'] == StorageErrorCode.SERVER_BUSY + retry_counter.simple_count(retry) + + # Act + with pytest.raises(HttpResponseError): + await service.create_container( + container_name, + raw_response_hook=response_handler, + retry_hook=assert_exception_is_present_on_retry_context) + + # Assert + assert retry_counter.count == 3 + # ------------------------------------------------------------------------------ diff --git a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/policies.py b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/policies.py index 4abfc9163a84..7f8caabbb710 100644 --- a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/policies.py +++ b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/policies.py @@ -33,7 +33,7 @@ from .authentication import StorageHttpChallenge from .constants import DEFAULT_OAUTH_SCOPE -from .models import LocationMode +from .models import LocationMode, StorageErrorCode try: _unicode_type = unicode # type: ignore @@ -88,6 +88,15 @@ def is_retry(response, mode): # pylint: disable=too-many-return-statements if status == 408: # Response code 408 is a timeout and should be retried. return True + if status >= 400: + error_code = response.http_response.headers.get('x-ms-copy-source-error-code') + retry_codes = [ + StorageErrorCode.OPERATION_TIMED_OUT, + StorageErrorCode.INTERNAL_ERROR, + StorageErrorCode.SERVER_BUSY + ] + if error_code in retry_codes: + return True return False if status >= 500: # Response codes above 500 with the exception of 501 Not Implemented and diff --git a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/response_handlers.py b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/response_handlers.py index e6b653035835..dc84c2dbfb25 100644 --- a/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/response_handlers.py +++ b/sdk/storage/azure-storage-file-datalake/azure/storage/filedatalake/_shared/response_handlers.py @@ -4,7 +4,7 @@ # license information. # -------------------------------------------------------------------------- import logging -from typing import NoReturn +from typing import Dict, NoReturn, Optional from xml.etree.ElementTree import Element from azure.core.exceptions import ( @@ -81,7 +81,7 @@ def return_raw_deserialized(response, *_): return response.http_response.location_mode, response.context[ContentDecodePolicy.CONTEXT_NAME] -def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # pylint:disable=too-many-statements +def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # pylint:disable=too-many-statements, too-many-branches raise_error = HttpResponseError serialized = False if not storage_error.response or storage_error.response.status_code in [200, 204]: @@ -92,8 +92,8 @@ def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # py serialized = True error_code = storage_error.response.headers.get('x-ms-error-code') error_message = storage_error.message - additional_data = {} - error_dict = {} + additional_data: Dict[str, Optional[str]] = {} + error_dict: Dict[str, Optional[str]] = {} try: error_body = ContentDecodePolicy.deserialize_from_http_generics(storage_error.response) try: @@ -104,7 +104,7 @@ def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # py # If it is an XML response if isinstance(error_body, Element): error_dict = { - child.tag.lower(): child.text + child.tag: child.text for child in error_body } # If it is a JSON response @@ -118,9 +118,14 @@ def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # py # If we extracted from a Json or XML response # There is a chance error_dict is just a string if error_dict and isinstance(error_dict, dict): - error_code = error_dict.get('code') - error_message = error_dict.get('message') - additional_data = {k: v for k, v in error_dict.items() if k not in {'code', 'message'}} + for k, v in error_dict.items(): + k_lower = k.lower() + if k_lower == 'code': + error_code = v + elif k_lower == 'message': + error_message = v + else: + additional_data[k] = v except DecodeError: pass diff --git a/sdk/storage/azure-storage-file-share/assets.json b/sdk/storage/azure-storage-file-share/assets.json index 75c74f0f875b..c084ac07ee98 100644 --- a/sdk/storage/azure-storage-file-share/assets.json +++ b/sdk/storage/azure-storage-file-share/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "python", "TagPrefix": "python/storage/azure-storage-file-share", - "Tag": "python/storage/azure-storage-file-share_890795be5a" + "Tag": "python/storage/azure-storage-file-share_a600655193" } diff --git a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_generated/_patch.py b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_generated/_patch.py index f99e77fef986..17dbc073e01b 100644 --- a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_generated/_patch.py +++ b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_generated/_patch.py @@ -25,6 +25,7 @@ # # -------------------------------------------------------------------------- + # This file is used for handwritten extensions to the generated code. Example: # https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/customize_code/how-to-patch-sdk-code.md def patch_sdk(): diff --git a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_generated/aio/_patch.py b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_generated/aio/_patch.py index f99e77fef986..17dbc073e01b 100644 --- a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_generated/aio/_patch.py +++ b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_generated/aio/_patch.py @@ -25,6 +25,7 @@ # # -------------------------------------------------------------------------- + # This file is used for handwritten extensions to the generated code. Example: # https://github.com/Azure/azure-sdk-for-python/blob/main/doc/dev/customize_code/how-to-patch-sdk-code.md def patch_sdk(): diff --git a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_generated/models/_models_py3.py b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_generated/models/_models_py3.py index 5dd7985911e5..7fe1a4ff1cb1 100644 --- a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_generated/models/_models_py3.py +++ b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_generated/models/_models_py3.py @@ -1543,26 +1543,51 @@ class StorageError(_serialization.Model): :ivar message: :vartype message: str + :ivar copy_source_status_code: + :vartype copy_source_status_code: int + :ivar copy_source_error_code: + :vartype copy_source_error_code: str + :ivar copy_source_error_message: + :vartype copy_source_error_message: str :ivar authentication_error_detail: :vartype authentication_error_detail: str """ _attribute_map = { "message": {"key": "Message", "type": "str"}, + "copy_source_status_code": {"key": "CopySourceStatusCode", "type": "int"}, + "copy_source_error_code": {"key": "CopySourceErrorCode", "type": "str"}, + "copy_source_error_message": {"key": "CopySourceErrorMessage", "type": "str"}, "authentication_error_detail": {"key": "AuthenticationErrorDetail", "type": "str"}, } def __init__( - self, *, message: Optional[str] = None, authentication_error_detail: Optional[str] = None, **kwargs: Any + self, + *, + message: Optional[str] = None, + copy_source_status_code: Optional[int] = None, + copy_source_error_code: Optional[str] = None, + copy_source_error_message: Optional[str] = None, + authentication_error_detail: Optional[str] = None, + **kwargs: Any ) -> None: """ :keyword message: :paramtype message: str + :keyword copy_source_status_code: + :paramtype copy_source_status_code: int + :keyword copy_source_error_code: + :paramtype copy_source_error_code: str + :keyword copy_source_error_message: + :paramtype copy_source_error_message: str :keyword authentication_error_detail: :paramtype authentication_error_detail: str """ super().__init__(**kwargs) self.message = message + self.copy_source_status_code = copy_source_status_code + self.copy_source_error_code = copy_source_error_code + self.copy_source_error_message = copy_source_error_message self.authentication_error_detail = authentication_error_detail diff --git a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/policies.py b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/policies.py index 82a9f9e8f2ba..705b1cd73f90 100644 --- a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/policies.py +++ b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/policies.py @@ -33,7 +33,7 @@ from .authentication import StorageHttpChallenge from .constants import DEFAULT_OAUTH_SCOPE -from .models import LocationMode +from .models import LocationMode, StorageErrorCode try: _unicode_type = unicode # type: ignore @@ -88,6 +88,15 @@ def is_retry(response, mode): # pylint: disable=too-many-return-statements if status == 408: # Response code 408 is a timeout and should be retried. return True + if status >= 400: + error_code = response.http_response.headers.get('x-ms-copy-source-error-code') + retry_codes = [ + StorageErrorCode.OPERATION_TIMED_OUT, + StorageErrorCode.INTERNAL_ERROR, + StorageErrorCode.SERVER_BUSY + ] + if error_code in retry_codes: + return True return False if status >= 500: # Response codes above 500 with the exception of 501 Not Implemented and diff --git a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/response_handlers.py b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/response_handlers.py index e6b653035835..dc84c2dbfb25 100644 --- a/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/response_handlers.py +++ b/sdk/storage/azure-storage-file-share/azure/storage/fileshare/_shared/response_handlers.py @@ -4,7 +4,7 @@ # license information. # -------------------------------------------------------------------------- import logging -from typing import NoReturn +from typing import Dict, NoReturn, Optional from xml.etree.ElementTree import Element from azure.core.exceptions import ( @@ -81,7 +81,7 @@ def return_raw_deserialized(response, *_): return response.http_response.location_mode, response.context[ContentDecodePolicy.CONTEXT_NAME] -def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # pylint:disable=too-many-statements +def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # pylint:disable=too-many-statements, too-many-branches raise_error = HttpResponseError serialized = False if not storage_error.response or storage_error.response.status_code in [200, 204]: @@ -92,8 +92,8 @@ def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # py serialized = True error_code = storage_error.response.headers.get('x-ms-error-code') error_message = storage_error.message - additional_data = {} - error_dict = {} + additional_data: Dict[str, Optional[str]] = {} + error_dict: Dict[str, Optional[str]] = {} try: error_body = ContentDecodePolicy.deserialize_from_http_generics(storage_error.response) try: @@ -104,7 +104,7 @@ def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # py # If it is an XML response if isinstance(error_body, Element): error_dict = { - child.tag.lower(): child.text + child.tag: child.text for child in error_body } # If it is a JSON response @@ -118,9 +118,14 @@ def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # py # If we extracted from a Json or XML response # There is a chance error_dict is just a string if error_dict and isinstance(error_dict, dict): - error_code = error_dict.get('code') - error_message = error_dict.get('message') - additional_data = {k: v for k, v in error_dict.items() if k not in {'code', 'message'}} + for k, v in error_dict.items(): + k_lower = k.lower() + if k_lower == 'code': + error_code = v + elif k_lower == 'message': + error_message = v + else: + additional_data[k] = v except DecodeError: pass diff --git a/sdk/storage/azure-storage-file-share/tests/test_file.py b/sdk/storage/azure-storage-file-share/tests/test_file.py index 86ea0dfec4f3..18d906af6a4c 100644 --- a/sdk/storage/azure-storage-file-share/tests/test_file.py +++ b/sdk/storage/azure-storage-file-share/tests/test_file.py @@ -1566,6 +1566,28 @@ def test_update_range_from_file_url_with_oauth(self, **kwargs): destination_file_client.upload_range_from_url(source_blob_client.url, offset=0, length=512, source_offset=0, source_authorization=token) + @FileSharePreparer() + @recorded_by_proxy + def test_update_range_from_file_url_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + self._setup(storage_account_name, storage_account_key) + source_file_name = 'testfile' + source_file_client = self._create_file(file_name=source_file_name) + data = b'abcdefghijklmnop' * 32 + source_file_client.upload_range(data, offset=0, length=512) + + destination_file_name = 'filetoupdate' + destination_file_client = self._create_empty_file(file_name=destination_file_name) + + with pytest.raises(HttpResponseError) as e: + destination_file_client.upload_range_from_url( + source_file_client.url, offset=0, length=512, source_offset=0) + + assert e.value.response.headers["x-ms-copy-source-status-code"] == "401" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "NoAuthenticationInformation" + @FileSharePreparer() @recorded_by_proxy def test_update_range_from_file_url_with_lease(self, **kwargs): @@ -2584,6 +2606,28 @@ def test_abort_copy_file_with_synchronous_copy_fails(self, **kwargs): # Assert assert copy_resp['copy_status'] == 'success' + @FileSharePreparer() + @recorded_by_proxy + def test_copy_file_async_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + self._setup(storage_account_name, storage_account_key) + + # Act + file_client = ShareFileClient( + self.account_url(storage_account_name, "file"), + share_name=self.share_name, + file_path="targetfile", + credential=storage_account_key) + + with pytest.raises(ResourceNotFoundError) as e: + file_client.start_copy_from_url("https://error.file.core.windows.net/") + + # Assert + assert e.value.response.headers["x-ms-copy-source-status-code"] == "400" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "InvalidQueryParameterValue" + @FileSharePreparer() @recorded_by_proxy def test_unicode_get_file_unicode_name(self, **kwargs): diff --git a/sdk/storage/azure-storage-file-share/tests/test_file_async.py b/sdk/storage/azure-storage-file-share/tests/test_file_async.py index 3b1317fb6a6d..e5981bb6a6b5 100644 --- a/sdk/storage/azure-storage-file-share/tests/test_file_async.py +++ b/sdk/storage/azure-storage-file-share/tests/test_file_async.py @@ -1597,6 +1597,34 @@ async def test_update_range_from_file_url_with_oauth(self, **kwargs): await destination_file_client.upload_range_from_url( source_blob_client.url, offset=0, length=512, source_offset=0, source_authorization=token) + @FileSharePreparer() + @recorded_by_proxy_async + async def test_update_range_from_file_url_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + self._setup(storage_account_name, storage_account_key) + source_file_name = 'testfile' + source_file_client = await self._create_file( + storage_account_name, + storage_account_key, + file_name=source_file_name) + data = b'abcdefghijklmnop' * 32 + await source_file_client.upload_range(data, offset=0, length=512) + + destination_file_name = 'filetoupdate' + destination_file_client = await self._create_empty_file( + storage_account_name, + storage_account_key, + file_name=destination_file_name) + + with pytest.raises(HttpResponseError) as e: + await destination_file_client.upload_range_from_url( + source_file_client.url, offset=0, length=512, source_offset=0) + + assert e.value.response.headers["x-ms-copy-source-status-code"] == "401" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "NoAuthenticationInformation" + @FileSharePreparer() @recorded_by_proxy_async async def test_update_range_from_file_url_with_lease(self, **kwargs): @@ -2636,6 +2664,29 @@ async def test_abort_copy_file_with_synchronous_copy_fails(self, **kwargs): # Assert assert copy_resp['copy_status'] == 'success' + @FileSharePreparer() + @recorded_by_proxy_async + async def test_copy_file_async_copy_source_error_and_status_code(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + self._setup(storage_account_name, storage_account_key) + await self._setup_share(storage_account_name, storage_account_key) + + # Act + file_client = ShareFileClient( + self.account_url(storage_account_name, "file"), + share_name=self.share_name, + file_path="targetfile", + credential=storage_account_key) + + with pytest.raises(ResourceNotFoundError) as e: + await file_client.start_copy_from_url("https://error.file.core.windows.net/") + + # Assert + assert e.value.response.headers["x-ms-copy-source-status-code"] == "400" + assert e.value.response.headers["x-ms-copy-source-error-code"] == "InvalidQueryParameterValue" + @FileSharePreparer() @recorded_by_proxy_async async def test_unicode_get_file_unicode_name(self, **kwargs): diff --git a/sdk/storage/azure-storage-file-share/tests/test_share.py b/sdk/storage/azure-storage-file-share/tests/test_share.py index 60855f2ca782..eb88bfd29a0c 100644 --- a/sdk/storage/azure-storage-file-share/tests/test_share.py +++ b/sdk/storage/azure-storage-file-share/tests/test_share.py @@ -980,7 +980,7 @@ def test_list_shares_account_sas_fails(self, **kwargs): # Assert assert e.value.error_code == StorageErrorCode.AUTHENTICATION_FAILED - assert "authenticationerrordetail" in e.value.message + assert "AuthenticationErrorDetail" in e.value.message @FileSharePreparer() @recorded_by_proxy diff --git a/sdk/storage/azure-storage-file-share/tests/test_share_async.py b/sdk/storage/azure-storage-file-share/tests/test_share_async.py index 987b36c3bb77..a04a18bb4977 100644 --- a/sdk/storage/azure-storage-file-share/tests/test_share_async.py +++ b/sdk/storage/azure-storage-file-share/tests/test_share_async.py @@ -995,7 +995,7 @@ async def test_list_shares_account_sas_fails(self, **kwargs): # Assert assert e.value.error_code == StorageErrorCode.AUTHENTICATION_FAILED - assert "authenticationerrordetail" in e.value.message + assert "AuthenticationErrorDetail" in e.value.message @FileSharePreparer() diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/policies.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/policies.py index 256da7bed4d9..5df16ac02e86 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/policies.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/policies.py @@ -33,7 +33,7 @@ from .authentication import StorageHttpChallenge from .constants import DEFAULT_OAUTH_SCOPE -from .models import LocationMode +from .models import LocationMode, StorageErrorCode try: _unicode_type = unicode # type: ignore @@ -88,6 +88,15 @@ def is_retry(response, mode): # pylint: disable=too-many-return-statements if status == 408: # Response code 408 is a timeout and should be retried. return True + if status >= 400: + error_code = response.http_response.headers.get('x-ms-copy-source-error-code') + retry_codes = [ + StorageErrorCode.OPERATION_TIMED_OUT, + StorageErrorCode.INTERNAL_ERROR, + StorageErrorCode.SERVER_BUSY + ] + if error_code in retry_codes: + return True return False if status >= 500: # Response codes above 500 with the exception of 501 Not Implemented and diff --git a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/response_handlers.py b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/response_handlers.py index e6b653035835..dc84c2dbfb25 100644 --- a/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/response_handlers.py +++ b/sdk/storage/azure-storage-queue/azure/storage/queue/_shared/response_handlers.py @@ -4,7 +4,7 @@ # license information. # -------------------------------------------------------------------------- import logging -from typing import NoReturn +from typing import Dict, NoReturn, Optional from xml.etree.ElementTree import Element from azure.core.exceptions import ( @@ -81,7 +81,7 @@ def return_raw_deserialized(response, *_): return response.http_response.location_mode, response.context[ContentDecodePolicy.CONTEXT_NAME] -def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # pylint:disable=too-many-statements +def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # pylint:disable=too-many-statements, too-many-branches raise_error = HttpResponseError serialized = False if not storage_error.response or storage_error.response.status_code in [200, 204]: @@ -92,8 +92,8 @@ def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # py serialized = True error_code = storage_error.response.headers.get('x-ms-error-code') error_message = storage_error.message - additional_data = {} - error_dict = {} + additional_data: Dict[str, Optional[str]] = {} + error_dict: Dict[str, Optional[str]] = {} try: error_body = ContentDecodePolicy.deserialize_from_http_generics(storage_error.response) try: @@ -104,7 +104,7 @@ def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # py # If it is an XML response if isinstance(error_body, Element): error_dict = { - child.tag.lower(): child.text + child.tag: child.text for child in error_body } # If it is a JSON response @@ -118,9 +118,14 @@ def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # py # If we extracted from a Json or XML response # There is a chance error_dict is just a string if error_dict and isinstance(error_dict, dict): - error_code = error_dict.get('code') - error_message = error_dict.get('message') - additional_data = {k: v for k, v in error_dict.items() if k not in {'code', 'message'}} + for k, v in error_dict.items(): + k_lower = k.lower() + if k_lower == 'code': + error_code = v + elif k_lower == 'message': + error_message = v + else: + additional_data[k] = v except DecodeError: pass