azure-storage-blob 12.21.0b1__py3-none-any.whl → 12.22.0__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/__init__.py +19 -18
- azure/storage/blob/_blob_client.py +470 -1555
- azure/storage/blob/_blob_client_helpers.py +1242 -0
- azure/storage/blob/_blob_service_client.py +93 -112
- azure/storage/blob/_blob_service_client_helpers.py +27 -0
- azure/storage/blob/_container_client.py +169 -376
- azure/storage/blob/_container_client_helpers.py +261 -0
- azure/storage/blob/_deserialize.py +68 -44
- azure/storage/blob/_download.py +375 -241
- azure/storage/blob/_encryption.py +14 -7
- azure/storage/blob/_generated/py.typed +1 -0
- azure/storage/blob/_lease.py +52 -63
- azure/storage/blob/_list_blobs_helper.py +129 -135
- azure/storage/blob/_models.py +480 -277
- azure/storage/blob/_quick_query_helper.py +30 -31
- azure/storage/blob/_serialize.py +38 -56
- azure/storage/blob/_shared/avro/datafile.py +1 -1
- azure/storage/blob/_shared/avro/datafile_async.py +1 -1
- azure/storage/blob/_shared/base_client.py +1 -1
- azure/storage/blob/_shared/base_client_async.py +1 -1
- azure/storage/blob/_shared/policies.py +8 -6
- azure/storage/blob/_shared/policies_async.py +3 -1
- azure/storage/blob/_shared/response_handlers.py +6 -2
- azure/storage/blob/_shared/shared_access_signature.py +2 -2
- azure/storage/blob/_shared/uploads.py +1 -1
- azure/storage/blob/_shared/uploads_async.py +1 -1
- azure/storage/blob/_shared_access_signature.py +70 -53
- azure/storage/blob/_upload_helpers.py +75 -68
- azure/storage/blob/_version.py +1 -1
- azure/storage/blob/aio/__init__.py +19 -11
- azure/storage/blob/aio/_blob_client_async.py +554 -301
- azure/storage/blob/aio/_blob_service_client_async.py +148 -97
- azure/storage/blob/aio/_container_client_async.py +282 -139
- azure/storage/blob/aio/_download_async.py +408 -283
- azure/storage/blob/aio/_lease_async.py +61 -60
- azure/storage/blob/aio/_list_blobs_helper.py +94 -96
- azure/storage/blob/aio/_models.py +60 -38
- azure/storage/blob/aio/_upload_helpers.py +75 -66
- {azure_storage_blob-12.21.0b1.dist-info → azure_storage_blob-12.22.0.dist-info}/METADATA +7 -7
- {azure_storage_blob-12.21.0b1.dist-info → azure_storage_blob-12.22.0.dist-info}/RECORD +43 -39
- {azure_storage_blob-12.21.0b1.dist-info → azure_storage_blob-12.22.0.dist-info}/WHEEL +1 -1
- {azure_storage_blob-12.21.0b1.dist-info → azure_storage_blob-12.22.0.dist-info}/LICENSE +0 -0
- {azure_storage_blob-12.21.0b1.dist-info → azure_storage_blob-12.22.0.dist-info}/top_level.txt +0 -0
@@ -5,35 +5,37 @@
|
|
5
5
|
# --------------------------------------------------------------------------
|
6
6
|
|
7
7
|
from io import SEEK_SET, UnsupportedOperation
|
8
|
-
from typing import TypeVar, TYPE_CHECKING
|
8
|
+
from typing import Any, cast, Dict, IO, Optional, TypeVar, TYPE_CHECKING
|
9
9
|
|
10
10
|
from azure.core.exceptions import ResourceExistsError, ResourceModifiedError, HttpResponseError
|
11
11
|
|
12
|
-
from .
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
12
|
+
from ._encryption import (
|
13
|
+
_ENCRYPTION_PROTOCOL_V1,
|
14
|
+
_ENCRYPTION_PROTOCOL_V2,
|
15
|
+
encrypt_blob,
|
16
|
+
GCMBlobEncryptionStream,
|
17
|
+
generate_blob_encryption_data,
|
18
|
+
get_adjusted_upload_size,
|
19
|
+
get_blob_encryptor_and_padder
|
20
20
|
)
|
21
21
|
from ._generated.models import (
|
22
|
-
BlockLookupList,
|
23
22
|
AppendPositionAccessConditions,
|
24
|
-
|
23
|
+
BlockLookupList,
|
24
|
+
ModifiedAccessConditions
|
25
25
|
)
|
26
|
-
from .
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
26
|
+
from ._shared.models import StorageErrorCode
|
27
|
+
from ._shared.response_handlers import process_storage_error, return_response_headers
|
28
|
+
from ._shared.uploads import (
|
29
|
+
AppendBlobChunkUploader,
|
30
|
+
BlockBlobChunkUploader,
|
31
|
+
PageBlobChunkUploader,
|
32
|
+
upload_data_chunks,
|
33
|
+
upload_substream_blocks
|
34
34
|
)
|
35
35
|
|
36
36
|
if TYPE_CHECKING:
|
37
|
+
from ._generated.operations import AppendBlobOperations, BlockBlobOperations, PageBlobOperations
|
38
|
+
from ._shared.models import StorageConfiguration
|
37
39
|
BlobLeaseClient = TypeVar("BlobLeaseClient")
|
38
40
|
|
39
41
|
_LARGE_BLOB_UPLOAD_MAX_READ_BUFFER_SIZE = 4 * 1024 * 1024
|
@@ -63,16 +65,17 @@ def _any_conditions(modified_access_conditions=None, **kwargs): # pylint: disab
|
|
63
65
|
|
64
66
|
|
65
67
|
def upload_block_blob( # pylint: disable=too-many-locals, too-many-statements
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
68
|
+
client: "BlockBlobOperations",
|
69
|
+
stream: IO,
|
70
|
+
overwrite: bool,
|
71
|
+
encryption_options: Dict[str, Any],
|
72
|
+
blob_settings: "StorageConfiguration",
|
73
|
+
headers: Dict[str, Any],
|
74
|
+
validate_content: bool,
|
75
|
+
max_concurrency: Optional[int],
|
76
|
+
length: Optional[int] = None,
|
77
|
+
**kwargs: Any
|
78
|
+
) -> Dict[str, Any]:
|
76
79
|
try:
|
77
80
|
if not overwrite and not _any_conditions(**kwargs):
|
78
81
|
kwargs['modified_access_conditions'].if_none_match = '*'
|
@@ -91,7 +94,7 @@ def upload_block_blob( # pylint: disable=too-many-locals, too-many-statements
|
|
91
94
|
|
92
95
|
# Do single put if the size is smaller than or equal config.max_single_put_size
|
93
96
|
if adjusted_count is not None and (adjusted_count <= blob_settings.max_single_put_size):
|
94
|
-
data = stream.read(length)
|
97
|
+
data = stream.read(length or -1)
|
95
98
|
if not isinstance(data, bytes):
|
96
99
|
raise TypeError('Blob data should be of type bytes.')
|
97
100
|
|
@@ -100,7 +103,7 @@ def upload_block_blob( # pylint: disable=too-many-locals, too-many-statements
|
|
100
103
|
headers['x-ms-meta-encryptiondata'] = encryption_data
|
101
104
|
|
102
105
|
response = client.upload(
|
103
|
-
body=data,
|
106
|
+
body=data, # type: ignore [arg-type]
|
104
107
|
content_length=adjusted_count,
|
105
108
|
blob_http_headers=blob_headers,
|
106
109
|
headers=headers,
|
@@ -118,7 +121,7 @@ def upload_block_blob( # pylint: disable=too-many-locals, too-many-statements
|
|
118
121
|
if progress_hook:
|
119
122
|
progress_hook(adjusted_count, adjusted_count)
|
120
123
|
|
121
|
-
return response
|
124
|
+
return cast(Dict[str, Any], response)
|
122
125
|
|
123
126
|
use_original_upload_path = blob_settings.use_byte_buffer or \
|
124
127
|
validate_content or encryption_options.get('required') or \
|
@@ -130,10 +133,10 @@ def upload_block_blob( # pylint: disable=too-many-locals, too-many-statements
|
|
130
133
|
total_size = length
|
131
134
|
encryptor, padder = None, None
|
132
135
|
if encryption_options and encryption_options.get('key'):
|
133
|
-
cek, iv,
|
136
|
+
cek, iv, encryption_metadata = generate_blob_encryption_data(
|
134
137
|
encryption_options['key'],
|
135
138
|
encryption_options['version'])
|
136
|
-
headers['x-ms-meta-encryptiondata'] =
|
139
|
+
headers['x-ms-meta-encryptiondata'] = encryption_metadata
|
137
140
|
|
138
141
|
if encryption_options['version'] == _ENCRYPTION_PROTOCOL_V1:
|
139
142
|
encryptor, padder = get_blob_encryptor_and_padder(cek, iv, True)
|
@@ -143,7 +146,9 @@ def upload_block_blob( # pylint: disable=too-many-locals, too-many-statements
|
|
143
146
|
# Adjust total_size for encryption V2
|
144
147
|
total_size = adjusted_count
|
145
148
|
# V2 wraps the data stream with an encryption stream
|
146
|
-
|
149
|
+
if cek is None:
|
150
|
+
raise ValueError("Generate encryption metadata failed. 'cek' is None.")
|
151
|
+
stream = GCMBlobEncryptionStream(cek, stream) # type: ignore [assignment]
|
147
152
|
|
148
153
|
block_ids = upload_data_chunks(
|
149
154
|
service=client,
|
@@ -175,7 +180,7 @@ def upload_block_blob( # pylint: disable=too-many-locals, too-many-statements
|
|
175
180
|
|
176
181
|
block_lookup = BlockLookupList(committed=[], uncommitted=[], latest=[])
|
177
182
|
block_lookup.latest = block_ids
|
178
|
-
return client.commit_block_list(
|
183
|
+
return cast(Dict[str, Any], client.commit_block_list(
|
179
184
|
block_lookup,
|
180
185
|
blob_http_headers=blob_headers,
|
181
186
|
cls=return_response_headers,
|
@@ -186,7 +191,7 @@ def upload_block_blob( # pylint: disable=too-many-locals, too-many-statements
|
|
186
191
|
immutability_policy_expiry=immutability_policy_expiry,
|
187
192
|
immutability_policy_mode=immutability_policy_mode,
|
188
193
|
legal_hold=legal_hold,
|
189
|
-
**kwargs)
|
194
|
+
**kwargs))
|
190
195
|
except HttpResponseError as error:
|
191
196
|
try:
|
192
197
|
process_storage_error(error)
|
@@ -197,16 +202,17 @@ def upload_block_blob( # pylint: disable=too-many-locals, too-many-statements
|
|
197
202
|
|
198
203
|
|
199
204
|
def upload_page_blob(
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
205
|
+
client: "PageBlobOperations",
|
206
|
+
overwrite: bool,
|
207
|
+
encryption_options: Dict[str, Any],
|
208
|
+
blob_settings: "StorageConfiguration",
|
209
|
+
headers: Dict[str, Any],
|
210
|
+
stream: IO,
|
211
|
+
length: Optional[int] = None,
|
212
|
+
validate_content: Optional[bool] = None,
|
213
|
+
max_concurrency: Optional[int] = None,
|
214
|
+
**kwargs: Any
|
215
|
+
) -> Dict[str, Any]:
|
210
216
|
try:
|
211
217
|
if not overwrite and not _any_conditions(**kwargs):
|
212
218
|
kwargs['modified_access_conditions'].if_none_match = '*'
|
@@ -232,18 +238,18 @@ def upload_page_blob(
|
|
232
238
|
blob_tags_string = kwargs.pop('blob_tags_string', None)
|
233
239
|
progress_hook = kwargs.pop('progress_hook', None)
|
234
240
|
|
235
|
-
response = client.create(
|
241
|
+
response = cast(Dict[str, Any], client.create(
|
236
242
|
content_length=0,
|
237
243
|
blob_content_length=length,
|
238
|
-
blob_sequence_number=None,
|
244
|
+
blob_sequence_number=None, # type: ignore [arg-type]
|
239
245
|
blob_http_headers=kwargs.pop('blob_headers', None),
|
240
246
|
blob_tags_string=blob_tags_string,
|
241
247
|
tier=tier,
|
242
248
|
cls=return_response_headers,
|
243
249
|
headers=headers,
|
244
|
-
**kwargs)
|
250
|
+
**kwargs))
|
245
251
|
if length == 0:
|
246
|
-
return response
|
252
|
+
return cast(Dict[str, Any], response)
|
247
253
|
|
248
254
|
if encryption_options and encryption_options.get('key'):
|
249
255
|
if encryption_options['version'] == _ENCRYPTION_PROTOCOL_V1:
|
@@ -252,7 +258,7 @@ def upload_page_blob(
|
|
252
258
|
kwargs['padder'] = padder
|
253
259
|
|
254
260
|
kwargs['modified_access_conditions'] = ModifiedAccessConditions(if_match=response['etag'])
|
255
|
-
return upload_data_chunks(
|
261
|
+
return cast(Dict[str, Any], upload_data_chunks(
|
256
262
|
service=client,
|
257
263
|
uploader_class=PageBlobChunkUploader,
|
258
264
|
total_size=length,
|
@@ -262,7 +268,7 @@ def upload_page_blob(
|
|
262
268
|
validate_content=validate_content,
|
263
269
|
progress_hook=progress_hook,
|
264
270
|
headers=headers,
|
265
|
-
**kwargs)
|
271
|
+
**kwargs))
|
266
272
|
|
267
273
|
except HttpResponseError as error:
|
268
274
|
try:
|
@@ -274,16 +280,17 @@ def upload_page_blob(
|
|
274
280
|
|
275
281
|
|
276
282
|
def upload_append_blob( # pylint: disable=unused-argument
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
283
|
+
client: "AppendBlobOperations",
|
284
|
+
overwrite: bool,
|
285
|
+
encryption_options: Dict[str, Any],
|
286
|
+
blob_settings: "StorageConfiguration",
|
287
|
+
headers: Dict[str, Any],
|
288
|
+
stream: IO,
|
289
|
+
length: Optional[int] = None,
|
290
|
+
validate_content: Optional[bool] = None,
|
291
|
+
max_concurrency: Optional[int] = None,
|
292
|
+
**kwargs: Any
|
293
|
+
) -> Dict[str, Any]:
|
287
294
|
try:
|
288
295
|
if length == 0:
|
289
296
|
return {}
|
@@ -302,7 +309,7 @@ def upload_append_blob( # pylint: disable=unused-argument
|
|
302
309
|
headers=headers,
|
303
310
|
blob_tags_string=blob_tags_string,
|
304
311
|
**kwargs)
|
305
|
-
return upload_data_chunks(
|
312
|
+
return cast(Dict[str, Any], upload_data_chunks(
|
306
313
|
service=client,
|
307
314
|
uploader_class=AppendBlobChunkUploader,
|
308
315
|
total_size=length,
|
@@ -313,9 +320,9 @@ def upload_append_blob( # pylint: disable=unused-argument
|
|
313
320
|
append_position_access_conditions=append_conditions,
|
314
321
|
progress_hook=progress_hook,
|
315
322
|
headers=headers,
|
316
|
-
**kwargs)
|
323
|
+
**kwargs))
|
317
324
|
except HttpResponseError as error:
|
318
|
-
if error.response.status_code != 404:
|
325
|
+
if error.response.status_code != 404: # type: ignore [union-attr]
|
319
326
|
raise
|
320
327
|
# rewind the request body if it is a stream
|
321
328
|
if hasattr(stream, 'read'):
|
@@ -331,7 +338,7 @@ def upload_append_blob( # pylint: disable=unused-argument
|
|
331
338
|
headers=headers,
|
332
339
|
blob_tags_string=blob_tags_string,
|
333
340
|
**kwargs)
|
334
|
-
return upload_data_chunks(
|
341
|
+
return cast(Dict[str, Any], upload_data_chunks(
|
335
342
|
service=client,
|
336
343
|
uploader_class=AppendBlobChunkUploader,
|
337
344
|
total_size=length,
|
@@ -342,6 +349,6 @@ def upload_append_blob( # pylint: disable=unused-argument
|
|
342
349
|
append_position_access_conditions=append_conditions,
|
343
350
|
progress_hook=progress_hook,
|
344
351
|
headers=headers,
|
345
|
-
**kwargs)
|
352
|
+
**kwargs))
|
346
353
|
except HttpResponseError as error:
|
347
354
|
process_storage_error(error)
|
azure/storage/blob/_version.py
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
|
8
8
|
import os
|
9
9
|
|
10
|
+
from typing import Any, AnyStr, Dict, cast, IO, Iterable, Optional, Union, TYPE_CHECKING
|
10
11
|
from ._list_blobs_helper import BlobPrefix
|
11
12
|
from .._models import BlobType
|
12
13
|
from .._shared.policies_async import ExponentialRetry, LinearRetry
|
@@ -16,13 +17,17 @@ from ._blob_service_client_async import BlobServiceClient
|
|
16
17
|
from ._lease_async import BlobLeaseClient
|
17
18
|
from ._download_async import StorageStreamDownloader
|
18
19
|
|
20
|
+
if TYPE_CHECKING:
|
21
|
+
from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential
|
22
|
+
from azure.core.credentials_async import AsyncTokenCredential
|
23
|
+
|
19
24
|
|
20
25
|
async def upload_blob_to_url(
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
+
blob_url: str,
|
27
|
+
data: Union[Iterable[AnyStr], IO[AnyStr]],
|
28
|
+
credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long
|
29
|
+
**kwargs: Any
|
30
|
+
) -> Dict[str, Any]:
|
26
31
|
"""Upload data to a given URL
|
27
32
|
|
28
33
|
The data will be uploaded as a block blob.
|
@@ -72,7 +77,10 @@ async def upload_blob_to_url(
|
|
72
77
|
:rtype: dict[str, Any]
|
73
78
|
"""
|
74
79
|
async with BlobClient.from_blob_url(blob_url, credential=credential) as client:
|
75
|
-
return await client.upload_blob(
|
80
|
+
return await cast(BlobClient, client).upload_blob(
|
81
|
+
data=data,
|
82
|
+
blob_type=BlobType.BLOCKBLOB,
|
83
|
+
**kwargs)
|
76
84
|
|
77
85
|
|
78
86
|
# Download data to specified open file-handle.
|
@@ -82,11 +90,11 @@ async def _download_to_stream(client, handle, **kwargs):
|
|
82
90
|
|
83
91
|
|
84
92
|
async def download_blob_from_url(
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
93
|
+
blob_url: str,
|
94
|
+
output: str,
|
95
|
+
credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long
|
96
|
+
**kwargs: Any
|
97
|
+
) -> None:
|
90
98
|
"""Download the contents of a blob to a local file or stream.
|
91
99
|
|
92
100
|
:param str blob_url:
|