azure-storage-blob 12.23.0b1__py3-none-any.whl → 12.23.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- azure/storage/blob/_container_client.py +6 -0
- azure/storage/blob/_container_client_helpers.py +7 -2
- azure/storage/blob/_encryption.py +13 -10
- azure/storage/blob/_generated/_azure_blob_storage.py +2 -1
- azure/storage/blob/_generated/_serialization.py +2 -0
- azure/storage/blob/_generated/aio/_azure_blob_storage.py +2 -1
- azure/storage/blob/_generated/aio/operations/_append_blob_operations.py +1 -7
- azure/storage/blob/_generated/aio/operations/_blob_operations.py +21 -47
- azure/storage/blob/_generated/aio/operations/_block_blob_operations.py +2 -10
- azure/storage/blob/_generated/aio/operations/_container_operations.py +13 -26
- azure/storage/blob/_generated/aio/operations/_page_blob_operations.py +3 -14
- azure/storage/blob/_generated/aio/operations/_service_operations.py +14 -17
- azure/storage/blob/_generated/operations/_append_blob_operations.py +1 -7
- azure/storage/blob/_generated/operations/_blob_operations.py +21 -47
- azure/storage/blob/_generated/operations/_block_blob_operations.py +2 -10
- azure/storage/blob/_generated/operations/_container_operations.py +13 -26
- azure/storage/blob/_generated/operations/_page_blob_operations.py +3 -14
- azure/storage/blob/_generated/operations/_service_operations.py +14 -17
- azure/storage/blob/_shared/base_client.py +2 -0
- azure/storage/blob/_shared/policies.py +8 -9
- azure/storage/blob/_shared/policies_async.py +18 -5
- azure/storage/blob/_version.py +1 -1
- azure/storage/blob/aio/_container_client_async.py +6 -0
- azure/storage/blob/aio/_download_async.py +94 -71
- {azure_storage_blob-12.23.0b1.dist-info → azure_storage_blob-12.23.1.dist-info}/METADATA +2 -2
- {azure_storage_blob-12.23.0b1.dist-info → azure_storage_blob-12.23.1.dist-info}/RECORD +29 -30
- {azure_storage_blob-12.23.0b1.dist-info → azure_storage_blob-12.23.1.dist-info}/WHEEL +1 -1
- azure/storage/blob/_generated/_vendor.py +0 -16
- {azure_storage_blob-12.23.0b1.dist-info → azure_storage_blob-12.23.1.dist-info}/LICENSE +0 -0
- {azure_storage_blob-12.23.0b1.dist-info → azure_storage_blob-12.23.1.dist-info}/top_level.txt +0 -0
@@ -15,17 +15,17 @@ from azure.core.exceptions import (
|
|
15
15
|
ResourceExistsError,
|
16
16
|
ResourceNotFoundError,
|
17
17
|
ResourceNotModifiedError,
|
18
|
+
StreamClosedError,
|
19
|
+
StreamConsumedError,
|
18
20
|
map_error,
|
19
21
|
)
|
20
22
|
from azure.core.pipeline import PipelineResponse
|
21
|
-
from azure.core.
|
22
|
-
from azure.core.rest import HttpRequest
|
23
|
+
from azure.core.rest import HttpRequest, HttpResponse
|
23
24
|
from azure.core.tracing.decorator import distributed_trace
|
24
25
|
from azure.core.utils import case_insensitive_dict
|
25
26
|
|
26
27
|
from .. import models as _models
|
27
28
|
from .._serialization import Serializer
|
28
|
-
from .._vendor import _convert_request
|
29
29
|
|
30
30
|
if sys.version_info >= (3, 9):
|
31
31
|
from collections.abc import MutableMapping
|
@@ -427,7 +427,6 @@ class ServiceOperations:
|
|
427
427
|
headers=_headers,
|
428
428
|
params=_params,
|
429
429
|
)
|
430
|
-
_request = _convert_request(_request)
|
431
430
|
_request.url = self._client.format_url(_request.url)
|
432
431
|
|
433
432
|
_stream = False
|
@@ -497,7 +496,6 @@ class ServiceOperations:
|
|
497
496
|
headers=_headers,
|
498
497
|
params=_params,
|
499
498
|
)
|
500
|
-
_request = _convert_request(_request)
|
501
499
|
_request.url = self._client.format_url(_request.url)
|
502
500
|
|
503
501
|
_stream = False
|
@@ -519,7 +517,7 @@ class ServiceOperations:
|
|
519
517
|
response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id"))
|
520
518
|
response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version"))
|
521
519
|
|
522
|
-
deserialized = self._deserialize("StorageServiceProperties", pipeline_response)
|
520
|
+
deserialized = self._deserialize("StorageServiceProperties", pipeline_response.http_response)
|
523
521
|
|
524
522
|
if cls:
|
525
523
|
return cls(pipeline_response, deserialized, response_headers) # type: ignore
|
@@ -572,7 +570,6 @@ class ServiceOperations:
|
|
572
570
|
headers=_headers,
|
573
571
|
params=_params,
|
574
572
|
)
|
575
|
-
_request = _convert_request(_request)
|
576
573
|
_request.url = self._client.format_url(_request.url)
|
577
574
|
|
578
575
|
_stream = False
|
@@ -595,7 +592,7 @@ class ServiceOperations:
|
|
595
592
|
response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version"))
|
596
593
|
response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date"))
|
597
594
|
|
598
|
-
deserialized = self._deserialize("StorageServiceStats", pipeline_response)
|
595
|
+
deserialized = self._deserialize("StorageServiceStats", pipeline_response.http_response)
|
599
596
|
|
600
597
|
if cls:
|
601
598
|
return cls(pipeline_response, deserialized, response_headers) # type: ignore
|
@@ -676,7 +673,6 @@ class ServiceOperations:
|
|
676
673
|
headers=_headers,
|
677
674
|
params=_params,
|
678
675
|
)
|
679
|
-
_request = _convert_request(_request)
|
680
676
|
_request.url = self._client.format_url(_request.url)
|
681
677
|
|
682
678
|
_stream = False
|
@@ -698,7 +694,7 @@ class ServiceOperations:
|
|
698
694
|
response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id"))
|
699
695
|
response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version"))
|
700
696
|
|
701
|
-
deserialized = self._deserialize("ListContainersSegmentResponse", pipeline_response)
|
697
|
+
deserialized = self._deserialize("ListContainersSegmentResponse", pipeline_response.http_response)
|
702
698
|
|
703
699
|
if cls:
|
704
700
|
return cls(pipeline_response, deserialized, response_headers) # type: ignore
|
@@ -761,7 +757,6 @@ class ServiceOperations:
|
|
761
757
|
headers=_headers,
|
762
758
|
params=_params,
|
763
759
|
)
|
764
|
-
_request = _convert_request(_request)
|
765
760
|
_request.url = self._client.format_url(_request.url)
|
766
761
|
|
767
762
|
_stream = False
|
@@ -784,7 +779,7 @@ class ServiceOperations:
|
|
784
779
|
response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version"))
|
785
780
|
response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date"))
|
786
781
|
|
787
|
-
deserialized = self._deserialize("UserDelegationKey", pipeline_response)
|
782
|
+
deserialized = self._deserialize("UserDelegationKey", pipeline_response.http_response)
|
788
783
|
|
789
784
|
if cls:
|
790
785
|
return cls(pipeline_response, deserialized, response_headers) # type: ignore
|
@@ -835,7 +830,6 @@ class ServiceOperations:
|
|
835
830
|
headers=_headers,
|
836
831
|
params=_params,
|
837
832
|
)
|
838
|
-
_request = _convert_request(_request)
|
839
833
|
_request.url = self._client.format_url(_request.url)
|
840
834
|
|
841
835
|
_stream = False
|
@@ -923,9 +917,9 @@ class ServiceOperations:
|
|
923
917
|
headers=_headers,
|
924
918
|
params=_params,
|
925
919
|
)
|
926
|
-
_request = _convert_request(_request)
|
927
920
|
_request.url = self._client.format_url(_request.url)
|
928
921
|
|
922
|
+
_decompress = kwargs.pop("decompress", True)
|
929
923
|
_stream = True
|
930
924
|
pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access
|
931
925
|
_request, stream=_stream, **kwargs
|
@@ -934,6 +928,10 @@ class ServiceOperations:
|
|
934
928
|
response = pipeline_response.http_response
|
935
929
|
|
936
930
|
if response.status_code not in [200]:
|
931
|
+
try:
|
932
|
+
response.read() # Load the body in memory and close the socket
|
933
|
+
except (StreamConsumedError, StreamClosedError):
|
934
|
+
pass
|
937
935
|
map_error(status_code=response.status_code, response=response, error_map=error_map)
|
938
936
|
error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response)
|
939
937
|
raise HttpResponseError(response=response, model=error)
|
@@ -943,7 +941,7 @@ class ServiceOperations:
|
|
943
941
|
response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id"))
|
944
942
|
response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version"))
|
945
943
|
|
946
|
-
deserialized = response.stream_download(self._client._pipeline)
|
944
|
+
deserialized = response.stream_download(self._client._pipeline, decompress=_decompress)
|
947
945
|
|
948
946
|
if cls:
|
949
947
|
return cls(pipeline_response, deserialized, response_headers) # type: ignore
|
@@ -1025,7 +1023,6 @@ class ServiceOperations:
|
|
1025
1023
|
headers=_headers,
|
1026
1024
|
params=_params,
|
1027
1025
|
)
|
1028
|
-
_request = _convert_request(_request)
|
1029
1026
|
_request.url = self._client.format_url(_request.url)
|
1030
1027
|
|
1031
1028
|
_stream = False
|
@@ -1048,7 +1045,7 @@ class ServiceOperations:
|
|
1048
1045
|
response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version"))
|
1049
1046
|
response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date"))
|
1050
1047
|
|
1051
|
-
deserialized = self._deserialize("FilterBlobSegment", pipeline_response)
|
1048
|
+
deserialized = self._deserialize("FilterBlobSegment", pipeline_response.http_response)
|
1052
1049
|
|
1053
1050
|
if cls:
|
1054
1051
|
return cls(pipeline_response, deserialized, response_headers) # type: ignore
|
@@ -76,6 +76,7 @@ class StorageAccountHostsMixin(object): # pylint: disable=too-many-instance-att
|
|
76
76
|
self._location_mode = kwargs.get("_location_mode", LocationMode.PRIMARY)
|
77
77
|
self._hosts = kwargs.get("_hosts")
|
78
78
|
self.scheme = parsed_url.scheme
|
79
|
+
self._is_localhost = False
|
79
80
|
|
80
81
|
if service not in ["blob", "queue", "file-share", "dfs"]:
|
81
82
|
raise ValueError(f"Invalid service: {service}")
|
@@ -85,6 +86,7 @@ class StorageAccountHostsMixin(object): # pylint: disable=too-many-instance-att
|
|
85
86
|
self.account_name = account[0] if len(account) > 1 else None
|
86
87
|
if not self.account_name and parsed_url.netloc.startswith("localhost") \
|
87
88
|
or parsed_url.netloc.startswith("127.0.0.1"):
|
89
|
+
self._is_localhost = True
|
88
90
|
self.account_name = parsed_url.path.strip("/")
|
89
91
|
|
90
92
|
self.credential = _format_shared_key_credential(self.account_name, credential)
|
@@ -35,11 +35,6 @@ from .authentication import AzureSigningError, StorageHttpChallenge
|
|
35
35
|
from .constants import DEFAULT_OAUTH_SCOPE
|
36
36
|
from .models import LocationMode
|
37
37
|
|
38
|
-
try:
|
39
|
-
_unicode_type = unicode # type: ignore
|
40
|
-
except NameError:
|
41
|
-
_unicode_type = str
|
42
|
-
|
43
38
|
if TYPE_CHECKING:
|
44
39
|
from azure.core.credentials import TokenCredential
|
45
40
|
from azure.core.pipeline.transport import ( # pylint: disable=non-abstract-transport-import
|
@@ -52,7 +47,7 @@ _LOGGER = logging.getLogger(__name__)
|
|
52
47
|
|
53
48
|
|
54
49
|
def encode_base64(data):
|
55
|
-
if isinstance(data,
|
50
|
+
if isinstance(data, str):
|
56
51
|
data = data.encode('utf-8')
|
57
52
|
encoded = base64.b64encode(data)
|
58
53
|
return encoded.decode('utf-8')
|
@@ -95,10 +90,14 @@ def is_retry(response, mode): # pylint: disable=too-many-return-statements
|
|
95
90
|
if status in [501, 505]:
|
96
91
|
return False
|
97
92
|
return True
|
93
|
+
return False
|
94
|
+
|
95
|
+
|
96
|
+
def is_checksum_retry(response):
|
98
97
|
# retry if invalid content md5
|
99
98
|
if response.context.get('validate_content', False) and response.http_response.headers.get('content-md5'):
|
100
99
|
computed_md5 = response.http_request.headers.get('content-md5', None) or \
|
101
|
-
|
100
|
+
encode_base64(StorageContentValidation.get_content_md5(response.http_response.body()))
|
102
101
|
if response.http_response.headers['content-md5'] != computed_md5:
|
103
102
|
return True
|
104
103
|
return False
|
@@ -301,7 +300,7 @@ class StorageResponseHook(HTTPPolicy):
|
|
301
300
|
|
302
301
|
response = self.next.send(request)
|
303
302
|
|
304
|
-
will_retry = is_retry(response, request.context.options.get('mode'))
|
303
|
+
will_retry = is_retry(response, request.context.options.get('mode')) or is_checksum_retry(response)
|
305
304
|
# Auth error could come from Bearer challenge, in which case this request will be made again
|
306
305
|
is_auth_error = response.http_response.status_code == 401
|
307
306
|
should_update_counts = not (will_retry or is_auth_error)
|
@@ -527,7 +526,7 @@ class StorageRetryPolicy(HTTPPolicy):
|
|
527
526
|
while retries_remaining:
|
528
527
|
try:
|
529
528
|
response = self.next.send(request)
|
530
|
-
if is_retry(response, retry_settings['mode']):
|
529
|
+
if is_retry(response, retry_settings['mode']) or is_checksum_retry(response):
|
531
530
|
retries_remaining = self.increment(
|
532
531
|
retry_settings,
|
533
532
|
request=request.http_request,
|
@@ -10,12 +10,12 @@ import logging
|
|
10
10
|
import random
|
11
11
|
from typing import Any, Dict, TYPE_CHECKING
|
12
12
|
|
13
|
-
from azure.core.exceptions import AzureError
|
13
|
+
from azure.core.exceptions import AzureError, StreamClosedError, StreamConsumedError
|
14
14
|
from azure.core.pipeline.policies import AsyncBearerTokenCredentialPolicy, AsyncHTTPPolicy
|
15
15
|
|
16
16
|
from .authentication import AzureSigningError, StorageHttpChallenge
|
17
17
|
from .constants import DEFAULT_OAUTH_SCOPE
|
18
|
-
from .policies import is_retry, StorageRetryPolicy
|
18
|
+
from .policies import encode_base64, is_retry, StorageContentValidation, StorageRetryPolicy
|
19
19
|
|
20
20
|
if TYPE_CHECKING:
|
21
21
|
from azure.core.credentials_async import AsyncTokenCredential
|
@@ -42,6 +42,20 @@ async def retry_hook(settings, **kwargs):
|
|
42
42
|
**kwargs)
|
43
43
|
|
44
44
|
|
45
|
+
async def is_checksum_retry(response):
|
46
|
+
# retry if invalid content md5
|
47
|
+
if response.context.get('validate_content', False) and response.http_response.headers.get('content-md5'):
|
48
|
+
try:
|
49
|
+
await response.http_response.read() # Load the body in memory and close the socket
|
50
|
+
except (StreamClosedError, StreamConsumedError):
|
51
|
+
pass
|
52
|
+
computed_md5 = response.http_request.headers.get('content-md5', None) or \
|
53
|
+
encode_base64(StorageContentValidation.get_content_md5(response.http_response.content))
|
54
|
+
if response.http_response.headers['content-md5'] != computed_md5:
|
55
|
+
return True
|
56
|
+
return False
|
57
|
+
|
58
|
+
|
45
59
|
class AsyncStorageResponseHook(AsyncHTTPPolicy):
|
46
60
|
|
47
61
|
def __init__(self, **kwargs): # pylint: disable=unused-argument
|
@@ -64,9 +78,8 @@ class AsyncStorageResponseHook(AsyncHTTPPolicy):
|
|
64
78
|
request.context.options.pop('raw_response_hook', self._response_callback)
|
65
79
|
|
66
80
|
response = await self.next.send(request)
|
67
|
-
|
81
|
+
will_retry = is_retry(response, request.context.options.get('mode')) or await is_checksum_retry(response)
|
68
82
|
|
69
|
-
will_retry = is_retry(response, request.context.options.get('mode'))
|
70
83
|
# Auth error could come from Bearer challenge, in which case this request will be made again
|
71
84
|
is_auth_error = response.http_response.status_code == 401
|
72
85
|
should_update_counts = not (will_retry or is_auth_error)
|
@@ -112,7 +125,7 @@ class AsyncStorageRetryPolicy(StorageRetryPolicy):
|
|
112
125
|
while retries_remaining:
|
113
126
|
try:
|
114
127
|
response = await self.next.send(request)
|
115
|
-
if is_retry(response, retry_settings['mode']):
|
128
|
+
if is_retry(response, retry_settings['mode']) or await is_checksum_retry(response):
|
116
129
|
retries_remaining = self.increment(
|
117
130
|
retry_settings,
|
118
131
|
request=request.http_request,
|
azure/storage/blob/_version.py
CHANGED
@@ -1406,6 +1406,8 @@ class ContainerClient(AsyncStorageAccountHostsMixin, StorageAccountHostsMixin, S
|
|
1406
1406
|
"""
|
1407
1407
|
if len(blobs) == 0:
|
1408
1408
|
return AsyncList([])
|
1409
|
+
if self._is_localhost:
|
1410
|
+
kwargs['url_prepend'] = self.account_name
|
1409
1411
|
|
1410
1412
|
reqs, options = _generate_delete_blobs_options(
|
1411
1413
|
self._query_str,
|
@@ -1485,6 +1487,8 @@ class ContainerClient(AsyncStorageAccountHostsMixin, StorageAccountHostsMixin, S
|
|
1485
1487
|
:return: An async iterator of responses, one for each blob in order
|
1486
1488
|
:rtype: asynciterator[~azure.core.pipeline.transport.AsyncHttpResponse]
|
1487
1489
|
"""
|
1490
|
+
if self._is_localhost:
|
1491
|
+
kwargs['url_prepend'] = self.account_name
|
1488
1492
|
reqs, options = _generate_set_tiers_options(
|
1489
1493
|
self._query_str,
|
1490
1494
|
self.container_name,
|
@@ -1544,6 +1548,8 @@ class ContainerClient(AsyncStorageAccountHostsMixin, StorageAccountHostsMixin, S
|
|
1544
1548
|
:return: An async iterator of responses, one for each blob in order
|
1545
1549
|
:rtype: asynciterator[~azure.core.pipeline.transport.AsyncHttpResponse]
|
1546
1550
|
"""
|
1551
|
+
if self._is_localhost:
|
1552
|
+
kwargs['url_prepend'] = self.account_name
|
1547
1553
|
reqs, options = _generate_set_tiers_options(
|
1548
1554
|
self._query_str,
|
1549
1555
|
self.container_name,
|
@@ -19,7 +19,7 @@ from typing import (
|
|
19
19
|
Tuple, TypeVar, Union, TYPE_CHECKING
|
20
20
|
)
|
21
21
|
|
22
|
-
from azure.core.exceptions import HttpResponseError
|
22
|
+
from azure.core.exceptions import DecodeError, HttpResponseError, IncompleteReadError
|
23
23
|
|
24
24
|
from .._shared.request_handlers import validate_and_format_range_headers
|
25
25
|
from .._shared.response_handlers import parse_length_from_content_range, process_storage_error
|
@@ -46,7 +46,8 @@ T = TypeVar('T', bytes, str)
|
|
46
46
|
async def process_content(data: Any, start_offset: int, end_offset: int, encryption: Dict[str, Any]) -> bytes:
|
47
47
|
if data is None:
|
48
48
|
raise ValueError("Response cannot be None.")
|
49
|
-
|
49
|
+
await data.response.read()
|
50
|
+
content = cast(bytes, data.response.content)
|
50
51
|
if encryption.get('key') is not None or encryption.get('resolver') is not None:
|
51
52
|
try:
|
52
53
|
return decrypt_blob(
|
@@ -120,20 +121,30 @@ class _AsyncChunkDownloader(_ChunkDownloader):
|
|
120
121
|
download_range[1],
|
121
122
|
check_content_md5=self.validate_content
|
122
123
|
)
|
123
|
-
try:
|
124
|
-
_, response = await cast(Awaitable[Any], self.client.download(
|
125
|
-
range=range_header,
|
126
|
-
range_get_content_md5=range_validation,
|
127
|
-
validate_content=self.validate_content,
|
128
|
-
data_stream_total=self.total_size,
|
129
|
-
download_stream_current=self.progress_total,
|
130
|
-
**self.request_options
|
131
|
-
))
|
132
124
|
|
133
|
-
|
134
|
-
|
125
|
+
retry_active = True
|
126
|
+
retry_total = 3
|
127
|
+
while retry_active:
|
128
|
+
try:
|
129
|
+
_, response = await cast(Awaitable[Any], self.client.download(
|
130
|
+
range=range_header,
|
131
|
+
range_get_content_md5=range_validation,
|
132
|
+
validate_content=self.validate_content,
|
133
|
+
data_stream_total=self.total_size,
|
134
|
+
download_stream_current=self.progress_total,
|
135
|
+
**self.request_options
|
136
|
+
))
|
137
|
+
except HttpResponseError as error:
|
138
|
+
process_storage_error(error)
|
135
139
|
|
136
|
-
|
140
|
+
try:
|
141
|
+
chunk_data = await process_content(response, offset[0], offset[1], self.encryption_options)
|
142
|
+
retry_active = False
|
143
|
+
except (IncompleteReadError, HttpResponseError, DecodeError) as error:
|
144
|
+
retry_total -= 1
|
145
|
+
if retry_total <= 0:
|
146
|
+
raise HttpResponseError(error, error=error) from error
|
147
|
+
await asyncio.sleep(1)
|
137
148
|
content_length = response.content_length
|
138
149
|
|
139
150
|
# This makes sure that if_match is set so that we can validate
|
@@ -342,66 +353,78 @@ class StorageStreamDownloader(Generic[T]): # pylint: disable=too-many-instance-
|
|
342
353
|
self._initial_range[1],
|
343
354
|
start_range_required=False,
|
344
355
|
end_range_required=False,
|
345
|
-
check_content_md5=self._validate_content
|
356
|
+
check_content_md5=self._validate_content
|
357
|
+
)
|
346
358
|
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
# Parse the total file size and adjust the download size if ranges
|
361
|
-
# were specified
|
362
|
-
self._file_size = parse_length_from_content_range(response.properties.content_range)
|
363
|
-
if self._file_size is None:
|
364
|
-
raise ValueError("Required Content-Range response header is missing or malformed.")
|
365
|
-
# Remove any extra encryption data size from blob size
|
366
|
-
self._file_size = adjust_blob_size_for_encryption(self._file_size, self._encryption_data)
|
367
|
-
|
368
|
-
if self._end_range is not None and self._start_range is not None:
|
369
|
-
# Use the length unless it is over the end of the file
|
370
|
-
self.size = min(self._file_size - self._start_range, self._end_range - self._start_range + 1)
|
371
|
-
elif self._start_range is not None:
|
372
|
-
self.size = self._file_size - self._start_range
|
373
|
-
else:
|
374
|
-
self.size = self._file_size
|
359
|
+
retry_active = True
|
360
|
+
retry_total = 3
|
361
|
+
while retry_active:
|
362
|
+
try:
|
363
|
+
location_mode, response = cast(Tuple[Optional[str], Any], await self._clients.blob.download(
|
364
|
+
range=range_header,
|
365
|
+
range_get_content_md5=range_validation,
|
366
|
+
validate_content=self._validate_content,
|
367
|
+
data_stream_total=None,
|
368
|
+
download_stream_current=0,
|
369
|
+
**self._request_options
|
370
|
+
))
|
375
371
|
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
#
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
self.
|
392
|
-
|
393
|
-
|
394
|
-
|
372
|
+
# Check the location we read from to ensure we use the same one
|
373
|
+
# for subsequent requests.
|
374
|
+
self._location_mode = location_mode
|
375
|
+
|
376
|
+
# Parse the total file size and adjust the download size if ranges
|
377
|
+
# were specified
|
378
|
+
self._file_size = parse_length_from_content_range(response.properties.content_range)
|
379
|
+
if self._file_size is None:
|
380
|
+
raise ValueError("Required Content-Range response header is missing or malformed.")
|
381
|
+
# Remove any extra encryption data size from blob size
|
382
|
+
self._file_size = adjust_blob_size_for_encryption(self._file_size, self._encryption_data)
|
383
|
+
|
384
|
+
if self._end_range is not None and self._start_range is not None:
|
385
|
+
# Use the length unless it is over the end of the file
|
386
|
+
self.size = min(self._file_size - self._start_range, self._end_range - self._start_range + 1)
|
387
|
+
elif self._start_range is not None:
|
388
|
+
self.size = self._file_size - self._start_range
|
389
|
+
else:
|
390
|
+
self.size = self._file_size
|
395
391
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
392
|
+
except HttpResponseError as error:
|
393
|
+
if self._start_range is None and error.response and error.status_code == 416:
|
394
|
+
# Get range will fail on an empty file. If the user did not
|
395
|
+
# request a range, do a regular get request in order to get
|
396
|
+
# any properties.
|
397
|
+
try:
|
398
|
+
_, response = cast(Tuple[Optional[Any], Any], await self._clients.blob.download(
|
399
|
+
validate_content=self._validate_content,
|
400
|
+
data_stream_total=0,
|
401
|
+
download_stream_current=0,
|
402
|
+
**self._request_options))
|
403
|
+
except HttpResponseError as e:
|
404
|
+
process_storage_error(e)
|
405
|
+
|
406
|
+
# Set the download size to empty
|
407
|
+
self.size = 0
|
408
|
+
self._file_size = 0
|
409
|
+
else:
|
410
|
+
process_storage_error(error)
|
411
|
+
|
412
|
+
try:
|
413
|
+
if self.size == 0:
|
414
|
+
self._current_content = b""
|
415
|
+
else:
|
416
|
+
self._current_content = await process_content(
|
417
|
+
response,
|
418
|
+
self._initial_offset[0],
|
419
|
+
self._initial_offset[1],
|
420
|
+
self._encryption_options
|
421
|
+
)
|
422
|
+
retry_active = False
|
423
|
+
except (IncompleteReadError, HttpResponseError, DecodeError) as error:
|
424
|
+
retry_total -= 1
|
425
|
+
if retry_total <= 0:
|
426
|
+
raise HttpResponseError(error, error=error) from error
|
427
|
+
await asyncio.sleep(1)
|
405
428
|
self._download_offset += len(self._current_content)
|
406
429
|
self._raw_download_offset += response.content_length
|
407
430
|
|
@@ -1,13 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: azure-storage-blob
|
3
|
-
Version: 12.23.
|
3
|
+
Version: 12.23.1
|
4
4
|
Summary: Microsoft Azure Blob Storage Client Library for Python
|
5
5
|
Home-page: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
6
6
|
Author: Microsoft Corporation
|
7
7
|
Author-email: ascl@microsoft.com
|
8
8
|
License: MIT License
|
9
9
|
Keywords: azure,azure sdk
|
10
|
-
Classifier: Development Status ::
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
11
11
|
Classifier: Programming Language :: Python
|
12
12
|
Classifier: Programming Language :: Python :: 3 :: Only
|
13
13
|
Classifier: Programming Language :: Python :: 3
|
@@ -3,11 +3,11 @@ azure/storage/blob/_blob_client.py,sha256=VFLd4oyTWawbxD1H7DBMfJHJcJNAUSXR-nzVxt
|
|
3
3
|
azure/storage/blob/_blob_client_helpers.py,sha256=7tfQzgpV-cnwYc4i-lZEr4YibDDkyl5RCPybQtJZ-i0,51905
|
4
4
|
azure/storage/blob/_blob_service_client.py,sha256=AKoFLHYt4pMREIeQQ3k892xs0XRfS6VV73365KLck-I,40366
|
5
5
|
azure/storage/blob/_blob_service_client_helpers.py,sha256=8jNCrF5rsgdJyAJQTdRR_mcOYuDCw4Nt9AirZk2RYUY,997
|
6
|
-
azure/storage/blob/_container_client.py,sha256=
|
7
|
-
azure/storage/blob/_container_client_helpers.py,sha256=
|
6
|
+
azure/storage/blob/_container_client.py,sha256=piG3Jv1lciW3FifKp_K1trQOtCorm4TTElbq2lMyiT0,84722
|
7
|
+
azure/storage/blob/_container_client_helpers.py,sha256=7H8-506B1iDoCvvwnx3masFjiFSzL1jt5gzIhPmnafA,12596
|
8
8
|
azure/storage/blob/_deserialize.py,sha256=VisgOi6WtpfkeOZ9lMcEAiZyg3A6AqR7oZO52WUXaWU,9937
|
9
9
|
azure/storage/blob/_download.py,sha256=nvj_IBZuSQWV1fO2iB0n_LAndv95SRhbscuGmxu9hHE,40069
|
10
|
-
azure/storage/blob/_encryption.py,sha256=
|
10
|
+
azure/storage/blob/_encryption.py,sha256=hRSsODop-NFAwO5HHu8sT5zQ1NuN4Absnr_NMhlCL44,47445
|
11
11
|
azure/storage/blob/_lease.py,sha256=ReF0nVfZE8p_clUGpebZPprBdXJ7lOGEqXmJUhvsX5U,18336
|
12
12
|
azure/storage/blob/_list_blobs_helper.py,sha256=smnTcpGSVkk93G0RI7YczhkIM0s0gx4bSGWj_DB8t_s,13160
|
13
13
|
azure/storage/blob/_models.py,sha256=c01JsL1fCAWecXfUUD6Dn50qpjV9r5ZiViXXCwNZVN4,66018
|
@@ -15,48 +15,47 @@ azure/storage/blob/_quick_query_helper.py,sha256=HO6ufvSEWQSaFJ4CanujE4IN7FYB6y1
|
|
15
15
|
azure/storage/blob/_serialize.py,sha256=5_MsQx2hVJnhNqlxP6_O7rksxEoGJXXSJSG3WIUd-iw,8146
|
16
16
|
azure/storage/blob/_shared_access_signature.py,sha256=VkoKyo5apDnKQ8wuEBp1C6MaKlqDHAZOf5wlqRcqdOA,35354
|
17
17
|
azure/storage/blob/_upload_helpers.py,sha256=-ZpqzST-wFdWqCm_I4oWGLTMQ5N0aYb3RHxaMvmf9Q4,14688
|
18
|
-
azure/storage/blob/_version.py,sha256=
|
18
|
+
azure/storage/blob/_version.py,sha256=UJeQ8inMo-t88amR6znjwTdSjvmma6OAm0OZr0xls6Q,331
|
19
19
|
azure/storage/blob/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
20
20
|
azure/storage/blob/_generated/__init__.py,sha256=J2H2yiFhRSsMCNKUI7gaYFIQ4_AAbWjPtzXdOsHFQFI,835
|
21
|
-
azure/storage/blob/_generated/_azure_blob_storage.py,sha256=
|
21
|
+
azure/storage/blob/_generated/_azure_blob_storage.py,sha256=VKK-9xxlF9DfNHuxlOxG6LB0XOZDLFdviW8O4W2AqeI,5737
|
22
22
|
azure/storage/blob/_generated/_configuration.py,sha256=PV4kKjbnHhg6nD30e_acUENnsLuEKKjYRHz1VqEk9UQ,2566
|
23
23
|
azure/storage/blob/_generated/_patch.py,sha256=MdyWs5y2w9_vYRWulELR-RV2uRYkjYpdB7nTVz2tVY4,1532
|
24
|
-
azure/storage/blob/_generated/_serialization.py,sha256=
|
25
|
-
azure/storage/blob/_generated/_vendor.py,sha256=e3w-rd6okoiCIB8rNMtF0fehAYFWNlshwiwTsIRkEH4,778
|
24
|
+
azure/storage/blob/_generated/_serialization.py,sha256=KsZWmQKoQbf9OUEEXmJ0UV-b9-lZRA1tCkkYt_a-4AI,78971
|
26
25
|
azure/storage/blob/_generated/py.typed,sha256=dcrsqJrcYfTX-ckLFJMTaj6mD8aDe2u0tkQG-ZYxnEg,26
|
27
26
|
azure/storage/blob/_generated/aio/__init__.py,sha256=J2H2yiFhRSsMCNKUI7gaYFIQ4_AAbWjPtzXdOsHFQFI,835
|
28
|
-
azure/storage/blob/_generated/aio/_azure_blob_storage.py,sha256=
|
27
|
+
azure/storage/blob/_generated/aio/_azure_blob_storage.py,sha256=FPnirEqJ8Nb3mWn0JPL3qb8_myyaz8UCdUQNfOW8xDs,5880
|
29
28
|
azure/storage/blob/_generated/aio/_configuration.py,sha256=Q4jfjKwpMOvSe2gS9lOdvwwsHvVtsJZN37AYrf4ySgg,2576
|
30
29
|
azure/storage/blob/_generated/aio/_patch.py,sha256=MdyWs5y2w9_vYRWulELR-RV2uRYkjYpdB7nTVz2tVY4,1532
|
31
30
|
azure/storage/blob/_generated/aio/operations/__init__.py,sha256=a5HiO2T3KzSSX8reO6fCwbKcwXqd0A6GIeF4t63XmTA,1181
|
32
|
-
azure/storage/blob/_generated/aio/operations/_append_blob_operations.py,sha256=
|
33
|
-
azure/storage/blob/_generated/aio/operations/_blob_operations.py,sha256=
|
34
|
-
azure/storage/blob/_generated/aio/operations/_block_blob_operations.py,sha256=
|
35
|
-
azure/storage/blob/_generated/aio/operations/_container_operations.py,sha256=
|
36
|
-
azure/storage/blob/_generated/aio/operations/_page_blob_operations.py,sha256=
|
31
|
+
azure/storage/blob/_generated/aio/operations/_append_blob_operations.py,sha256=FtuAMOUlqQp0fGAowxhghw7Py0jeYblsScLPMAgRn_8,37309
|
32
|
+
azure/storage/blob/_generated/aio/operations/_blob_operations.py,sha256=x6rz3T7RZNBJtOmyc0TcnOYJMOKA8TbYi8emYIbbKkE,166403
|
33
|
+
azure/storage/blob/_generated/aio/operations/_block_blob_operations.py,sha256=DUu5kWJwMfjvKHI-5SIB_Nn9_Ea8H4KctB_YtdixICk,60610
|
34
|
+
azure/storage/blob/_generated/aio/operations/_container_operations.py,sha256=8BJPTAGM1pn8gvB4jQqDq2gYxp6Pb8lzkzJ5FzC9XzY,90725
|
35
|
+
azure/storage/blob/_generated/aio/operations/_page_blob_operations.py,sha256=jp5RocDr6Lp3gQRoGnNug8sVoX_G9G7vG-658KS8Z84,74976
|
37
36
|
azure/storage/blob/_generated/aio/operations/_patch.py,sha256=pYl0jxVFr3Yu0RHRFIgN3NwFrEZr1uL-7xbEXGgJzBw,794
|
38
|
-
azure/storage/blob/_generated/aio/operations/_service_operations.py,sha256=
|
37
|
+
azure/storage/blob/_generated/aio/operations/_service_operations.py,sha256=8UAsZEKJjT1a4sulVCWZ7B2_PVhL4WSVnFpU0BIlqrs,35960
|
39
38
|
azure/storage/blob/_generated/models/__init__.py,sha256=qOh_WzGPNB7Do1XSXfRosHQJ94zx1G5dVXpZdkNKLuM,6303
|
40
39
|
azure/storage/blob/_generated/models/_azure_blob_storage_enums.py,sha256=o1I_SPnUKEsx2Aec-goLDw6eqZMyTVqFxg7tKpSYg0I,13049
|
41
40
|
azure/storage/blob/_generated/models/_models_py3.py,sha256=JXhdrOvO8VKo_Vhz-cqnXI1gfDf6nkrcBDC7Cz0rL_s,110612
|
42
41
|
azure/storage/blob/_generated/models/_patch.py,sha256=pYl0jxVFr3Yu0RHRFIgN3NwFrEZr1uL-7xbEXGgJzBw,794
|
43
42
|
azure/storage/blob/_generated/operations/__init__.py,sha256=a5HiO2T3KzSSX8reO6fCwbKcwXqd0A6GIeF4t63XmTA,1181
|
44
|
-
azure/storage/blob/_generated/operations/_append_blob_operations.py,sha256=
|
45
|
-
azure/storage/blob/_generated/operations/_blob_operations.py,sha256=
|
46
|
-
azure/storage/blob/_generated/operations/_block_blob_operations.py,sha256=
|
47
|
-
azure/storage/blob/_generated/operations/_container_operations.py,sha256=
|
48
|
-
azure/storage/blob/_generated/operations/_page_blob_operations.py,sha256=
|
43
|
+
azure/storage/blob/_generated/operations/_append_blob_operations.py,sha256=T7Kqy8hKbPTmN7nF0M3XgKP-Pewyn0oGQ5mKTmhbnTs,55981
|
44
|
+
azure/storage/blob/_generated/operations/_blob_operations.py,sha256=AGGNddKS8creiGVfpf3mPxvP_0FvgnUV3xHMDml36xk,232577
|
45
|
+
azure/storage/blob/_generated/operations/_block_blob_operations.py,sha256=XgZ4fwZpbBrEw8ztdq7aeCKE4t7yfsGZXKkxlw72gqY,91414
|
46
|
+
azure/storage/blob/_generated/operations/_container_operations.py,sha256=XuWEdsPzEwdDeM9FpD1s6S9q5-YggBUUn848snvWCKU,128351
|
47
|
+
azure/storage/blob/_generated/operations/_page_blob_operations.py,sha256=Gj6szO76q2_3YGUNdznMz9E9UNMZKvarm4DCc5IO18o,112375
|
49
48
|
azure/storage/blob/_generated/operations/_patch.py,sha256=pYl0jxVFr3Yu0RHRFIgN3NwFrEZr1uL-7xbEXGgJzBw,794
|
50
|
-
azure/storage/blob/_generated/operations/_service_operations.py,sha256=
|
49
|
+
azure/storage/blob/_generated/operations/_service_operations.py,sha256=nq9AqOcEM340nLxhzaUlzta3gD0KyOZZhCI_808uYT0,49818
|
51
50
|
azure/storage/blob/_shared/__init__.py,sha256=Ohb4NSCuB9VXGEqjU2o9VZ5L98-a7c8KWZvrujnSFk8,1477
|
52
51
|
azure/storage/blob/_shared/authentication.py,sha256=KfUKWkjItNJxUTWNcCNusYfnENy-XbVelHlZM8fWc0Y,9450
|
53
|
-
azure/storage/blob/_shared/base_client.py,sha256=
|
52
|
+
azure/storage/blob/_shared/base_client.py,sha256=JJ0xwN2GGzfwB2a37TEyotxcL1WL-rvalAc1RnPWl9A,18628
|
54
53
|
azure/storage/blob/_shared/base_client_async.py,sha256=z1dyRk2XSurRn69CwKA_lQYC7kRFOMkwhIr-InPP5t8,11918
|
55
54
|
azure/storage/blob/_shared/constants.py,sha256=0TnhBNEaZpVq0vECmLoXWSzCajtn9WOlfOfzbMApRb4,620
|
56
55
|
azure/storage/blob/_shared/models.py,sha256=aDydzgBj2_-WfnlT1-nOhJt-FHxOU8BG0T0K68BejNk,24907
|
57
56
|
azure/storage/blob/_shared/parser.py,sha256=ACpdtwf6lhzmA0ukT3PmxpGVpimVXTy_mMSdixC55R8,1955
|
58
|
-
azure/storage/blob/_shared/policies.py,sha256=
|
59
|
-
azure/storage/blob/_shared/policies_async.py,sha256=
|
57
|
+
azure/storage/blob/_shared/policies.py,sha256=ZesS3wGCCtDvUGXmNUKGiRlRA9wKYFeYdiElhKpHJo0,30917
|
58
|
+
azure/storage/blob/_shared/policies_async.py,sha256=Fo0zEvHU5rBSSuD55mmYroD0XCSXEx3L6STcr27kMnE,13497
|
60
59
|
azure/storage/blob/_shared/request_handlers.py,sha256=0G9eyzMY_8BlLfHA6jbJF75ENcu3xqZ33bHfSRi9HTM,9755
|
61
60
|
azure/storage/blob/_shared/response_handlers.py,sha256=wqZ1hGRDTwh3GkRB0gPSjgm_7TP2quZc_ex4pYThW-8,9190
|
62
61
|
azure/storage/blob/_shared/shared_access_signature.py,sha256=ov8h9CStKwlfZBtlj54jeckpzuVjYcYvJNKgxQByZ9o,11130
|
@@ -71,15 +70,15 @@ azure/storage/blob/_shared/avro/schema.py,sha256=Z9qcHIEBDbXxkBBs_HYbEWHlZtAbvT3
|
|
71
70
|
azure/storage/blob/aio/__init__.py,sha256=tVgeGWdfxG32uyJxAE32waysCOGt93S_EeuQLJz7vEM,8344
|
72
71
|
azure/storage/blob/aio/_blob_client_async.py,sha256=wx76W_LrUDQ2vqBbgvS3RzKLtrnXbAe2INRtLXjtu2g,180606
|
73
72
|
azure/storage/blob/aio/_blob_service_client_async.py,sha256=3rOewtzrDmjUoYKwM0EBUwYLizqp3KHx71lEHDcN_Yw,41260
|
74
|
-
azure/storage/blob/aio/_container_client_async.py,sha256=
|
75
|
-
azure/storage/blob/aio/_download_async.py,sha256=
|
73
|
+
azure/storage/blob/aio/_container_client_async.py,sha256=sJaxiKPqA2iDBaDQtI4dnPIrsdmLc_aqSXPk_AJ4QME,85402
|
74
|
+
azure/storage/blob/aio/_download_async.py,sha256=zneaszZj69VblrUkWocBjvhvXedQJfJweL4uTqc9TpE,38078
|
76
75
|
azure/storage/blob/aio/_encryption_async.py,sha256=spbWeycNMj38H5ynZ03FRtRu0L0tnl1lQn5UJT6HMAY,2518
|
77
76
|
azure/storage/blob/aio/_lease_async.py,sha256=dy4_KZYuIhlxEvYO4GLTKdZz4UzFkpxcm7zfino6geE,18638
|
78
77
|
azure/storage/blob/aio/_list_blobs_helper.py,sha256=cbrJcaGVfOvVCcLYd5dGx-jV3JjSvKfDIi2AQjf79qs,9920
|
79
78
|
azure/storage/blob/aio/_models.py,sha256=fdv7OQc6utrGBIS8FSNuBhYK5Q65o1TbKvdeeQaeUOc,8143
|
80
79
|
azure/storage/blob/aio/_upload_helpers.py,sha256=zROsVN6PK2Cn59Ysq08Ide5T1IGG2yH7oK9ZCn5uQXs,14038
|
81
|
-
azure_storage_blob-12.23.
|
82
|
-
azure_storage_blob-12.23.
|
83
|
-
azure_storage_blob-12.23.
|
84
|
-
azure_storage_blob-12.23.
|
85
|
-
azure_storage_blob-12.23.
|
80
|
+
azure_storage_blob-12.23.1.dist-info/LICENSE,sha256=_VMkgdgo4ToLE8y1mOAjOKNhd0BnWoYu5r3BVBto6T0,1073
|
81
|
+
azure_storage_blob-12.23.1.dist-info/METADATA,sha256=MsP96yVjSewFFWu2tOQgUL0AiNG1-MlHxML8LCReiyY,26252
|
82
|
+
azure_storage_blob-12.23.1.dist-info/WHEEL,sha256=HiCZjzuy6Dw0hdX5R3LCFPDmFS4BWl8H-8W39XfmgX4,91
|
83
|
+
azure_storage_blob-12.23.1.dist-info/top_level.txt,sha256=S7DhWV9m80TBzAhOFjxDUiNbKszzoThbnrSz5MpbHSQ,6
|
84
|
+
azure_storage_blob-12.23.1.dist-info/RECORD,,
|