azure-storage-blob 12.21.0b1__py3-none-any.whl → 12.23.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 +176 -377
- azure/storage/blob/_container_client_helpers.py +266 -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/_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/_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 +39 -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 +3 -1
- azure/storage/blob/_shared/base_client_async.py +1 -1
- azure/storage/blob/_shared/policies.py +16 -15
- azure/storage/blob/_shared/policies_async.py +21 -6
- azure/storage/blob/_shared/response_handlers.py +6 -2
- azure/storage/blob/_shared/shared_access_signature.py +21 -3
- azure/storage/blob/_shared/uploads.py +1 -1
- azure/storage/blob/_shared/uploads_async.py +1 -1
- azure/storage/blob/_shared_access_signature.py +110 -52
- 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 +289 -140
- azure/storage/blob/aio/_download_async.py +485 -337
- 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.23.0.dist-info}/METADATA +7 -7
- azure_storage_blob-12.23.0.dist-info/RECORD +84 -0
- {azure_storage_blob-12.21.0b1.dist-info → azure_storage_blob-12.23.0.dist-info}/WHEEL +1 -1
- azure/storage/blob/_generated/_vendor.py +0 -16
- azure_storage_blob-12.21.0b1.dist-info/RECORD +0 -81
- {azure_storage_blob-12.21.0b1.dist-info → azure_storage_blob-12.23.0.dist-info}/LICENSE +0 -0
- {azure_storage_blob-12.21.0b1.dist-info → azure_storage_blob-12.23.0.dist-info}/top_level.txt +0 -0
@@ -5,25 +5,20 @@
|
|
5
5
|
# --------------------------------------------------------------------------
|
6
6
|
# pylint: disable=docstring-keyword-should-match-keyword-only
|
7
7
|
|
8
|
-
from typing import (
|
9
|
-
|
8
|
+
from typing import (
|
9
|
+
Any, Callable, Optional, Union,
|
10
|
+
TYPE_CHECKING
|
10
11
|
)
|
11
12
|
from urllib.parse import parse_qs
|
12
13
|
|
13
14
|
from ._shared import sign_string, url_quote
|
14
15
|
from ._shared.constants import X_MS_VERSION
|
15
16
|
from ._shared.models import Services, UserDelegationKey
|
16
|
-
from ._shared.shared_access_signature import SharedAccessSignature, _SharedAccessHelper
|
17
|
-
QueryStringConstants
|
17
|
+
from ._shared.shared_access_signature import QueryStringConstants, SharedAccessSignature, _SharedAccessHelper
|
18
18
|
|
19
19
|
if TYPE_CHECKING:
|
20
20
|
from datetime import datetime
|
21
|
-
from ..blob import
|
22
|
-
ResourceTypes,
|
23
|
-
AccountSasPermissions,
|
24
|
-
ContainerSasPermissions,
|
25
|
-
BlobSasPermissions
|
26
|
-
)
|
21
|
+
from ..blob import AccountSasPermissions, BlobSasPermissions, ContainerSasPermissions, ResourceTypes
|
27
22
|
|
28
23
|
|
29
24
|
class BlobQueryStringConstants(object):
|
@@ -38,13 +33,17 @@ class BlobSharedAccessSignature(SharedAccessSignature):
|
|
38
33
|
generate_*_shared_access_signature method directly.
|
39
34
|
'''
|
40
35
|
|
41
|
-
def __init__(
|
36
|
+
def __init__(
|
37
|
+
self, account_name: str,
|
38
|
+
account_key: Optional[str] = None,
|
39
|
+
user_delegation_key: Optional[UserDelegationKey] = None
|
40
|
+
) -> None:
|
42
41
|
'''
|
43
42
|
:param str account_name:
|
44
43
|
The storage account name used to generate the shared access signatures.
|
45
|
-
:param str account_key:
|
44
|
+
:param Optional[str] account_key:
|
46
45
|
The access key to generate the shares access signatures.
|
47
|
-
:param ~azure.storage.blob.models.UserDelegationKey user_delegation_key:
|
46
|
+
:param Optional[~azure.storage.blob.models.UserDelegationKey] user_delegation_key:
|
48
47
|
Instead of an account key, the user could pass in a user delegation key.
|
49
48
|
A user delegation key can be obtained from the service by authenticating with an AAD identity;
|
50
49
|
this can be accomplished by calling get_user_delegation_key on any Blob service object.
|
@@ -52,11 +51,25 @@ class BlobSharedAccessSignature(SharedAccessSignature):
|
|
52
51
|
super(BlobSharedAccessSignature, self).__init__(account_name, account_key, x_ms_version=X_MS_VERSION)
|
53
52
|
self.user_delegation_key = user_delegation_key
|
54
53
|
|
55
|
-
def generate_blob(
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
54
|
+
def generate_blob(
|
55
|
+
self, container_name: str,
|
56
|
+
blob_name: str,
|
57
|
+
snapshot: Optional[str] = None,
|
58
|
+
version_id: Optional[str] = None,
|
59
|
+
permission: Optional[Union["BlobSasPermissions", str]] = None,
|
60
|
+
expiry: Optional[Union["datetime", str]] = None,
|
61
|
+
start: Optional[Union["datetime", str]] = None,
|
62
|
+
policy_id: Optional[str] = None,
|
63
|
+
ip: Optional[str] = None,
|
64
|
+
protocol: Optional[str] = None,
|
65
|
+
cache_control: Optional[str] = None,
|
66
|
+
content_disposition: Optional[str] = None,
|
67
|
+
content_encoding: Optional[str] = None,
|
68
|
+
content_language: Optional[str] = None,
|
69
|
+
content_type: Optional[str] = None,
|
70
|
+
sts_hook: Optional[Callable[[str], None]] = None,
|
71
|
+
**kwargs: Any
|
72
|
+
) -> str:
|
60
73
|
'''
|
61
74
|
Generates a shared access signature for the blob or one of its snapshots.
|
62
75
|
Use the returned signature with the sas_token parameter of any BlobService.
|
@@ -66,7 +79,7 @@ class BlobSharedAccessSignature(SharedAccessSignature):
|
|
66
79
|
:param str blob_name:
|
67
80
|
Name of blob.
|
68
81
|
:param str snapshot:
|
69
|
-
The snapshot parameter is an opaque
|
82
|
+
The snapshot parameter is an opaque datetime value that,
|
70
83
|
when present, specifies the blob snapshot to grant permission.
|
71
84
|
:param str version_id:
|
72
85
|
An optional blob version ID. This parameter is only applicable for versioning-enabled
|
@@ -123,6 +136,10 @@ class BlobSharedAccessSignature(SharedAccessSignature):
|
|
123
136
|
:param str content_type:
|
124
137
|
Response header value for Content-Type when resource is accessed
|
125
138
|
using this shared access signature.
|
139
|
+
:param sts_hook:
|
140
|
+
For debugging purposes only. If provided, the hook is called with the string to sign
|
141
|
+
that was used to generate the SAS.
|
142
|
+
:type sts_hook: Optional[Callable[[str], None]]
|
126
143
|
:return: A Shared Access Signature (sas) token.
|
127
144
|
:rtype: str
|
128
145
|
'''
|
@@ -146,13 +163,27 @@ class BlobSharedAccessSignature(SharedAccessSignature):
|
|
146
163
|
sas.add_resource_signature(self.account_name, self.account_key, resource_path,
|
147
164
|
user_delegation_key=self.user_delegation_key)
|
148
165
|
|
166
|
+
if sts_hook is not None:
|
167
|
+
sts_hook(sas.string_to_sign)
|
168
|
+
|
149
169
|
return sas.get_token()
|
150
170
|
|
151
|
-
def generate_container(
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
171
|
+
def generate_container(
|
172
|
+
self, container_name: str,
|
173
|
+
permission: Optional[Union["ContainerSasPermissions", str]] = None,
|
174
|
+
expiry: Optional[Union["datetime", str]] = None,
|
175
|
+
start: Optional[Union["datetime", str]] = None,
|
176
|
+
policy_id: Optional[str] = None,
|
177
|
+
ip: Optional[str] = None,
|
178
|
+
protocol: Optional[str] = None,
|
179
|
+
cache_control: Optional[str] = None,
|
180
|
+
content_disposition: Optional[str] = None,
|
181
|
+
content_encoding: Optional[str] = None,
|
182
|
+
content_language: Optional[str] = None,
|
183
|
+
content_type: Optional[str] = None,
|
184
|
+
sts_hook: Optional[Callable[[str], None]] = None,
|
185
|
+
**kwargs: Any
|
186
|
+
) -> str:
|
156
187
|
'''
|
157
188
|
Generates a shared access signature for the container.
|
158
189
|
Use the returned signature with the sas_token parameter of any BlobService.
|
@@ -209,6 +240,10 @@ class BlobSharedAccessSignature(SharedAccessSignature):
|
|
209
240
|
:param str content_type:
|
210
241
|
Response header value for Content-Type when resource is accessed
|
211
242
|
using this shared access signature.
|
243
|
+
:param sts_hook:
|
244
|
+
For debugging purposes only. If provided, the hook is called with the string to sign
|
245
|
+
that was used to generate the SAS.
|
246
|
+
:type sts_hook: Optional[Callable[[str], None]]
|
212
247
|
:return: A Shared Access Signature (sas) token.
|
213
248
|
:rtype: str
|
214
249
|
'''
|
@@ -223,6 +258,10 @@ class BlobSharedAccessSignature(SharedAccessSignature):
|
|
223
258
|
sas.add_info_for_hns_account(**kwargs)
|
224
259
|
sas.add_resource_signature(self.account_name, self.account_key, container_name,
|
225
260
|
user_delegation_key=self.user_delegation_key)
|
261
|
+
|
262
|
+
if sts_hook is not None:
|
263
|
+
sts_hook(sas.string_to_sign)
|
264
|
+
|
226
265
|
return sas.get_token()
|
227
266
|
|
228
267
|
|
@@ -297,8 +336,9 @@ class _BlobSharedAccessHelper(_SharedAccessHelper):
|
|
297
336
|
self._add_query(QueryStringConstants.SIGNED_SIGNATURE,
|
298
337
|
sign_string(account_key if user_delegation_key is None else user_delegation_key.value,
|
299
338
|
string_to_sign))
|
339
|
+
self.string_to_sign = string_to_sign
|
300
340
|
|
301
|
-
def get_token(self):
|
341
|
+
def get_token(self) -> str:
|
302
342
|
# a conscious decision was made to exclude the timestamp in the generated token
|
303
343
|
# this is to avoid having two snapshot ids in the query parameters when the user appends the snapshot timestamp
|
304
344
|
exclude = [BlobQueryStringConstants.SIGNED_TIMESTAMP]
|
@@ -316,6 +356,7 @@ def generate_account_sas(
|
|
316
356
|
ip: Optional[str] = None,
|
317
357
|
*,
|
318
358
|
services: Union[Services, str] = Services(blob=True),
|
359
|
+
sts_hook: Optional[Callable[[str], None]] = None,
|
319
360
|
**kwargs: Any
|
320
361
|
) -> str:
|
321
362
|
"""Generates a shared access signature for the blob service.
|
@@ -357,6 +398,10 @@ def generate_account_sas(
|
|
357
398
|
Specifies the protocol permitted for a request made. The default value is https.
|
358
399
|
:keyword str encryption_scope:
|
359
400
|
Specifies the encryption scope for a request made so that all write operations will be service encrypted.
|
401
|
+
:keyword sts_hook:
|
402
|
+
For debugging purposes only. If provided, the hook is called with the string to sign
|
403
|
+
that was used to generate the SAS.
|
404
|
+
:paramtype sts_hook: Optional[Callable[[str], None]]
|
360
405
|
:return: A Shared Access Signature (sas) token.
|
361
406
|
:rtype: str
|
362
407
|
|
@@ -377,23 +422,25 @@ def generate_account_sas(
|
|
377
422
|
expiry=expiry,
|
378
423
|
start=start,
|
379
424
|
ip=ip,
|
425
|
+
sts_hook=sts_hook,
|
380
426
|
**kwargs
|
381
|
-
)
|
427
|
+
)
|
382
428
|
|
383
429
|
|
384
430
|
def generate_container_sas(
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
431
|
+
account_name: str,
|
432
|
+
container_name: str,
|
433
|
+
account_key: Optional[str] = None,
|
434
|
+
user_delegation_key: Optional[UserDelegationKey] = None,
|
435
|
+
permission: Optional[Union["ContainerSasPermissions", str]] = None,
|
436
|
+
expiry: Optional[Union["datetime", str]] = None,
|
437
|
+
start: Optional[Union["datetime", str]] = None,
|
438
|
+
policy_id: Optional[str] = None,
|
439
|
+
ip: Optional[str] = None,
|
440
|
+
*,
|
441
|
+
sts_hook: Optional[Callable[[str], None]] = None,
|
442
|
+
**kwargs: Any
|
443
|
+
) -> str:
|
397
444
|
"""Generates a shared access signature for a container.
|
398
445
|
|
399
446
|
Use the returned signature with the credential parameter of any BlobServiceClient,
|
@@ -465,6 +512,10 @@ def generate_container_sas(
|
|
465
512
|
:keyword str correlation_id:
|
466
513
|
The correlation id to correlate the storage audit logs with the audit logs used by the principal
|
467
514
|
generating and distributing the SAS. This can only be used when generating a SAS with delegation key.
|
515
|
+
:keyword sts_hook:
|
516
|
+
For debugging purposes only. If provided, the hook is called with the string to sign
|
517
|
+
that was used to generate the SAS.
|
518
|
+
:paramtype sts_hook: Optional[Callable[[str], None]]
|
468
519
|
:return: A Shared Access Signature (sas) token.
|
469
520
|
:rtype: str
|
470
521
|
|
@@ -497,25 +548,27 @@ def generate_container_sas(
|
|
497
548
|
start=start,
|
498
549
|
policy_id=policy_id,
|
499
550
|
ip=ip,
|
551
|
+
sts_hook=sts_hook,
|
500
552
|
**kwargs
|
501
553
|
)
|
502
554
|
|
503
555
|
|
504
556
|
def generate_blob_sas(
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
557
|
+
account_name: str,
|
558
|
+
container_name: str,
|
559
|
+
blob_name: str,
|
560
|
+
snapshot: Optional[str] = None,
|
561
|
+
account_key: Optional[str] = None,
|
562
|
+
user_delegation_key: Optional[UserDelegationKey] = None,
|
563
|
+
permission: Optional[Union["BlobSasPermissions", str]] = None,
|
564
|
+
expiry: Optional[Union["datetime", str]] = None,
|
565
|
+
start: Optional[Union["datetime", str]] = None,
|
566
|
+
policy_id: Optional[str] = None,
|
567
|
+
ip: Optional[str] = None,
|
568
|
+
*,
|
569
|
+
sts_hook: Optional[Callable[[str], None]] = None,
|
570
|
+
**kwargs: Any
|
571
|
+
) -> str:
|
519
572
|
"""Generates a shared access signature for a blob.
|
520
573
|
|
521
574
|
Use the returned signature with the credential parameter of any BlobServiceClient,
|
@@ -599,6 +652,10 @@ def generate_blob_sas(
|
|
599
652
|
:keyword str correlation_id:
|
600
653
|
The correlation id to correlate the storage audit logs with the audit logs used by the principal
|
601
654
|
generating and distributing the SAS. This can only be used when generating a SAS with delegation key.
|
655
|
+
:keyword sts_hook:
|
656
|
+
For debugging purposes only. If provided, the hook is called with the string to sign
|
657
|
+
that was used to generate the SAS.
|
658
|
+
:paramtype sts_hook: Optional[Callable[[str], None]]
|
602
659
|
:return: A Shared Access Signature (sas) token.
|
603
660
|
:rtype: str
|
604
661
|
"""
|
@@ -628,6 +685,7 @@ def generate_blob_sas(
|
|
628
685
|
start=start,
|
629
686
|
policy_id=policy_id,
|
630
687
|
ip=ip,
|
688
|
+
sts_hook=sts_hook,
|
631
689
|
**kwargs
|
632
690
|
)
|
633
691
|
|
@@ -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:
|