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,93 +5,96 @@
|
|
5
5
|
# --------------------------------------------------------------------------
|
6
6
|
# pylint: disable=too-many-lines, docstring-keyword-should-match-keyword-only
|
7
7
|
|
8
|
+
import warnings
|
9
|
+
from datetime import datetime
|
8
10
|
from functools import partial
|
9
|
-
from io import BytesIO
|
10
11
|
from typing import (
|
11
|
-
Any, AnyStr,
|
12
|
+
Any, AnyStr, cast, Dict, IO, Iterable, List, Optional, overload, Tuple, Union,
|
12
13
|
TYPE_CHECKING
|
13
14
|
)
|
14
|
-
from urllib.parse import urlparse, quote, unquote
|
15
|
-
import warnings
|
16
|
-
|
17
15
|
from typing_extensions import Self
|
18
16
|
|
19
|
-
from azure.core.exceptions import
|
17
|
+
from azure.core.exceptions import HttpResponseError, ResourceExistsError, ResourceNotFoundError
|
20
18
|
from azure.core.paging import ItemPaged
|
21
19
|
from azure.core.pipeline import Pipeline
|
22
20
|
from azure.core.tracing.decorator import distributed_trace
|
23
|
-
from .
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
21
|
+
from ._blob_client_helpers import (
|
22
|
+
_abort_copy_options,
|
23
|
+
_append_block_from_url_options,
|
24
|
+
_append_block_options,
|
25
|
+
_clear_page_options,
|
26
|
+
_commit_block_list_options,
|
27
|
+
_create_append_blob_options,
|
28
|
+
_create_page_blob_options,
|
29
|
+
_create_snapshot_options,
|
30
|
+
_delete_blob_options,
|
31
|
+
_download_blob_options,
|
32
|
+
_format_url,
|
33
|
+
_from_blob_url,
|
34
|
+
_get_blob_tags_options,
|
35
|
+
_get_block_list_result,
|
36
|
+
_get_page_ranges_options,
|
37
|
+
_parse_url,
|
38
|
+
_quick_query_options,
|
39
|
+
_resize_blob_options,
|
40
|
+
_seal_append_blob_options,
|
41
|
+
_set_blob_metadata_options,
|
42
|
+
_set_blob_tags_options,
|
43
|
+
_set_http_headers_options,
|
44
|
+
_set_sequence_number_options,
|
45
|
+
_stage_block_from_url_options,
|
46
|
+
_stage_block_options,
|
47
|
+
_start_copy_from_url_options,
|
48
|
+
_upload_blob_from_url_options,
|
49
|
+
_upload_blob_options,
|
50
|
+
_upload_page_options,
|
51
|
+
_upload_pages_from_url_options
|
51
52
|
)
|
52
53
|
from ._deserialize import (
|
53
|
-
get_page_ranges_result,
|
54
54
|
deserialize_blob_properties,
|
55
|
-
|
56
|
-
|
57
|
-
|
55
|
+
deserialize_pipeline_response_into_cls,
|
56
|
+
get_page_ranges_result,
|
57
|
+
parse_tags
|
58
58
|
)
|
59
59
|
from ._download import StorageStreamDownloader
|
60
|
-
from ._encryption import
|
60
|
+
from ._encryption import StorageEncryptionMixin, _ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION
|
61
|
+
from ._generated import AzureBlobStorage
|
62
|
+
from ._generated.models import CpkInfo
|
61
63
|
from ._lease import BlobLeaseClient
|
62
|
-
from ._models import
|
63
|
-
DelimitedJsonDialect, DelimitedTextDialect, PageRangePaged, PageRange
|
64
|
+
from ._models import BlobBlock, BlobProperties, BlobQueryError, BlobType, PageRange, PageRangePaged
|
64
65
|
from ._quick_query_helper import BlobQueryReader
|
66
|
+
from ._shared.base_client import parse_connection_str, StorageAccountHostsMixin, TransportWrapper
|
67
|
+
from ._shared.response_handlers import process_storage_error, return_response_headers
|
68
|
+
from ._serialize import (
|
69
|
+
get_access_conditions,
|
70
|
+
get_api_version,
|
71
|
+
get_modify_conditions,
|
72
|
+
get_version_id
|
73
|
+
)
|
65
74
|
from ._upload_helpers import (
|
66
|
-
upload_block_blob,
|
67
75
|
upload_append_blob,
|
68
|
-
|
69
|
-
|
76
|
+
upload_block_blob,
|
77
|
+
upload_page_blob
|
70
78
|
)
|
71
79
|
|
72
80
|
if TYPE_CHECKING:
|
73
81
|
from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential, TokenCredential
|
74
|
-
from
|
75
|
-
from ._generated.models import BlockList
|
82
|
+
from azure.storage.blob import ContainerClient
|
76
83
|
from ._models import (
|
77
84
|
ContentSettings,
|
78
85
|
ImmutabilityPolicy,
|
79
86
|
PremiumPageBlobTier,
|
80
|
-
|
81
|
-
|
87
|
+
SequenceNumberAction,
|
88
|
+
StandardBlobTier
|
82
89
|
)
|
83
90
|
|
84
|
-
_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION = (
|
85
|
-
'The require_encryption flag is set, but encryption is not supported'
|
86
|
-
' for this method.')
|
87
|
-
|
88
91
|
|
89
92
|
class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: disable=too-many-public-methods
|
90
93
|
"""A client to interact with a specific blob, although that blob may not yet exist.
|
91
94
|
|
92
95
|
For more optional configuration, please click
|
93
96
|
`here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
94
|
-
#optional-configuration>`
|
97
|
+
#optional-configuration>`__.
|
95
98
|
|
96
99
|
:param str account_url:
|
97
100
|
The URI to the storage account. In order to create a client given the full URI to the blob,
|
@@ -157,36 +160,26 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
157
160
|
:caption: Creating the BlobClient from a SAS URL to a blob.
|
158
161
|
"""
|
159
162
|
def __init__(
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
raise ValueError("Account URL must be a string.") from exc
|
172
|
-
parsed_url = urlparse(account_url.rstrip('/'))
|
173
|
-
|
174
|
-
if not (container_name and blob_name):
|
175
|
-
raise ValueError("Please specify a container name and blob name.")
|
176
|
-
if not parsed_url.netloc:
|
177
|
-
raise ValueError(f"Invalid URL: {account_url}")
|
178
|
-
|
179
|
-
path_snapshot, sas_token = parse_query(parsed_url.query)
|
180
|
-
|
163
|
+
self, account_url: str,
|
164
|
+
container_name: str,
|
165
|
+
blob_name: str,
|
166
|
+
snapshot: Optional[Union[str, Dict[str, Any]]] = None,
|
167
|
+
credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
|
168
|
+
**kwargs: Any
|
169
|
+
) -> None:
|
170
|
+
parsed_url, sas_token, path_snapshot = _parse_url(
|
171
|
+
account_url=account_url,
|
172
|
+
container_name=container_name,
|
173
|
+
blob_name=blob_name)
|
181
174
|
self.container_name = container_name
|
182
175
|
self.blob_name = blob_name
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
176
|
+
|
177
|
+
if snapshot is not None and hasattr(snapshot, 'snapshot'):
|
178
|
+
self.snapshot = snapshot.snapshot
|
179
|
+
elif isinstance(snapshot, dict):
|
180
|
+
self.snapshot = snapshot['snapshot']
|
181
|
+
else:
|
182
|
+
self.snapshot = snapshot or path_snapshot
|
190
183
|
self.version_id = kwargs.pop('version_id', None)
|
191
184
|
|
192
185
|
# This parameter is used for the hierarchy traversal. Give precedence to credential.
|
@@ -194,33 +187,25 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
194
187
|
self._query_str, credential = self._format_query_string(sas_token, credential, snapshot=self.snapshot)
|
195
188
|
super(BlobClient, self).__init__(parsed_url, service='blob', credential=credential, **kwargs)
|
196
189
|
self._client = AzureBlobStorage(self.url, base_url=self.url, pipeline=self._pipeline)
|
197
|
-
self._client._config.version = get_api_version(kwargs) # pylint: disable=protected-access
|
190
|
+
self._client._config.version = get_api_version(kwargs) # type: ignore [assignment] # pylint: disable=protected-access
|
198
191
|
self._configure_encryption(kwargs)
|
199
192
|
|
200
|
-
def _format_url(self, hostname):
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
source_scheme = parsed_source_url.scheme
|
209
|
-
source_hostname = parsed_source_url.netloc.rstrip('/')
|
210
|
-
source_path = unquote(parsed_source_url.path)
|
211
|
-
source_query = parsed_source_url.query
|
212
|
-
result = [f"{source_scheme}://{source_hostname}{quote(source_path, safe='~/')}"]
|
213
|
-
if source_query:
|
214
|
-
result.append(source_query)
|
215
|
-
return '?'.join(result)
|
193
|
+
def _format_url(self, hostname: str) -> str:
|
194
|
+
return _format_url(
|
195
|
+
container_name=self.container_name,
|
196
|
+
scheme=self.scheme,
|
197
|
+
blob_name=self.blob_name,
|
198
|
+
query_str=self._query_str,
|
199
|
+
hostname=hostname
|
200
|
+
)
|
216
201
|
|
217
202
|
@classmethod
|
218
203
|
def from_blob_url(
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
204
|
+
cls, blob_url: str,
|
205
|
+
credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
|
206
|
+
snapshot: Optional[Union[str, Dict[str, Any]]] = None,
|
207
|
+
**kwargs: Any
|
208
|
+
) -> Self:
|
224
209
|
"""Create BlobClient from a blob url. This doesn't support customized blob url with '/' in blob name.
|
225
210
|
|
226
211
|
:param str blob_url:
|
@@ -254,48 +239,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
254
239
|
:returns: A Blob client.
|
255
240
|
:rtype: ~azure.storage.blob.BlobClient
|
256
241
|
"""
|
257
|
-
|
258
|
-
if not blob_url.lower().startswith('http'):
|
259
|
-
blob_url = "https://" + blob_url
|
260
|
-
except AttributeError as exc:
|
261
|
-
raise ValueError("Blob URL must be a string.") from exc
|
262
|
-
parsed_url = urlparse(blob_url.rstrip('/'))
|
263
|
-
|
264
|
-
if not parsed_url.netloc:
|
265
|
-
raise ValueError(f"Invalid URL: {blob_url}")
|
266
|
-
|
267
|
-
account_path = ""
|
268
|
-
if ".core." in parsed_url.netloc:
|
269
|
-
# .core. is indicating non-customized url. Blob name with directory info can also be parsed.
|
270
|
-
path_blob = parsed_url.path.lstrip('/').split('/', maxsplit=1)
|
271
|
-
elif "localhost" in parsed_url.netloc or "127.0.0.1" in parsed_url.netloc:
|
272
|
-
path_blob = parsed_url.path.lstrip('/').split('/', maxsplit=2)
|
273
|
-
account_path += '/' + path_blob[0]
|
274
|
-
else:
|
275
|
-
# for customized url. blob name that has directory info cannot be parsed.
|
276
|
-
path_blob = parsed_url.path.lstrip('/').split('/')
|
277
|
-
if len(path_blob) > 2:
|
278
|
-
account_path = "/" + "/".join(path_blob[:-2])
|
279
|
-
|
280
|
-
account_url = f"{parsed_url.scheme}://{parsed_url.netloc.rstrip('/')}{account_path}?{parsed_url.query}"
|
281
|
-
|
282
|
-
msg_invalid_url = "Invalid URL. Provide a blob_url with a valid blob and container name."
|
283
|
-
if len(path_blob) <= 1:
|
284
|
-
raise ValueError(msg_invalid_url)
|
285
|
-
container_name, blob_name = unquote(path_blob[-2]), unquote(path_blob[-1])
|
286
|
-
if not container_name or not blob_name:
|
287
|
-
raise ValueError(msg_invalid_url)
|
288
|
-
|
289
|
-
path_snapshot, _ = parse_query(parsed_url.query)
|
290
|
-
if snapshot:
|
291
|
-
try:
|
292
|
-
path_snapshot = snapshot.snapshot # type: ignore
|
293
|
-
except AttributeError:
|
294
|
-
try:
|
295
|
-
path_snapshot = snapshot['snapshot'] # type: ignore
|
296
|
-
except TypeError:
|
297
|
-
path_snapshot = snapshot
|
298
|
-
|
242
|
+
account_url, container_name, blob_name, path_snapshot = _from_blob_url(blob_url=blob_url, snapshot=snapshot)
|
299
243
|
return cls(
|
300
244
|
account_url, container_name=container_name, blob_name=blob_name,
|
301
245
|
snapshot=path_snapshot, credential=credential, **kwargs
|
@@ -303,13 +247,13 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
303
247
|
|
304
248
|
@classmethod
|
305
249
|
def from_connection_string(
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
250
|
+
cls, conn_str: str,
|
251
|
+
container_name: str,
|
252
|
+
blob_name: str,
|
253
|
+
snapshot: Optional[Union[str, Dict[str, Any]]] = None,
|
254
|
+
credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
|
255
|
+
**kwargs: Any
|
256
|
+
) -> Self:
|
313
257
|
"""Create BlobClient from a Connection String.
|
314
258
|
|
315
259
|
:param str conn_str:
|
@@ -361,8 +305,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
361
305
|
)
|
362
306
|
|
363
307
|
@distributed_trace
|
364
|
-
def get_account_information(self, **kwargs):
|
365
|
-
# type: (**Any) -> Dict[str, str]
|
308
|
+
def get_account_information(self, **kwargs: Any) -> Dict[str, str]:
|
366
309
|
"""Gets information related to the storage account in which the blob resides.
|
367
310
|
|
368
311
|
The information can also be retrieved if the user has a SAS to a container or blob.
|
@@ -372,149 +315,12 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
372
315
|
:rtype: dict(str, str)
|
373
316
|
"""
|
374
317
|
try:
|
375
|
-
return self._client.blob.get_account_info(cls=return_response_headers, **kwargs)
|
318
|
+
return cast(Dict[str, str], self._client.blob.get_account_info(cls=return_response_headers, **kwargs))
|
376
319
|
except HttpResponseError as error:
|
377
320
|
process_storage_error(error)
|
378
321
|
|
379
|
-
def _upload_blob_options( # pylint:disable=too-many-statements
|
380
|
-
self, data: Union[bytes, str, Iterable[AnyStr], AsyncIterable[AnyStr], IO[AnyStr]],
|
381
|
-
blob_type: Union[str, BlobType] = BlobType.BlockBlob,
|
382
|
-
length: Optional[int] = None,
|
383
|
-
metadata: Optional[Dict[str, str]] = None,
|
384
|
-
**kwargs
|
385
|
-
) -> Dict[str, Any]:
|
386
|
-
if self.require_encryption and not self.key_encryption_key:
|
387
|
-
raise ValueError("Encryption required but no key was provided.")
|
388
|
-
encryption_options = {
|
389
|
-
'required': self.require_encryption,
|
390
|
-
'version': self.encryption_version,
|
391
|
-
'key': self.key_encryption_key,
|
392
|
-
'resolver': self.key_resolver_function,
|
393
|
-
}
|
394
|
-
|
395
|
-
encoding = kwargs.pop('encoding', 'UTF-8')
|
396
|
-
if isinstance(data, str):
|
397
|
-
data = data.encode(encoding)
|
398
|
-
if length is None:
|
399
|
-
length = get_length(data)
|
400
|
-
if isinstance(data, bytes):
|
401
|
-
data = data[:length]
|
402
|
-
|
403
|
-
if isinstance(data, bytes):
|
404
|
-
stream = BytesIO(data)
|
405
|
-
elif hasattr(data, 'read'):
|
406
|
-
stream = data
|
407
|
-
elif hasattr(data, '__iter__') and not isinstance(data, (list, tuple, set, dict)):
|
408
|
-
stream = IterStreamer(data, encoding=encoding)
|
409
|
-
elif hasattr(data, '__aiter__'):
|
410
|
-
stream = AsyncIterStreamer(data, encoding=encoding)
|
411
|
-
else:
|
412
|
-
raise TypeError(f"Unsupported data type: {type(data)}")
|
413
|
-
|
414
|
-
validate_content = kwargs.pop('validate_content', False)
|
415
|
-
content_settings = kwargs.pop('content_settings', None)
|
416
|
-
overwrite = kwargs.pop('overwrite', False)
|
417
|
-
max_concurrency = kwargs.pop('max_concurrency', 1)
|
418
|
-
cpk = kwargs.pop('cpk', None)
|
419
|
-
cpk_info = None
|
420
|
-
if cpk:
|
421
|
-
if self.scheme.lower() != 'https':
|
422
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
423
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
424
|
-
encryption_algorithm=cpk.algorithm)
|
425
|
-
kwargs['cpk_info'] = cpk_info
|
426
|
-
|
427
|
-
headers = kwargs.pop('headers', {})
|
428
|
-
headers.update(add_metadata_headers(metadata))
|
429
|
-
kwargs['lease_access_conditions'] = get_access_conditions(kwargs.pop('lease', None))
|
430
|
-
kwargs['modified_access_conditions'] = get_modify_conditions(kwargs)
|
431
|
-
kwargs['cpk_scope_info'] = get_cpk_scope_info(kwargs)
|
432
|
-
if content_settings:
|
433
|
-
kwargs['blob_headers'] = BlobHTTPHeaders(
|
434
|
-
blob_cache_control=content_settings.cache_control,
|
435
|
-
blob_content_type=content_settings.content_type,
|
436
|
-
blob_content_md5=content_settings.content_md5,
|
437
|
-
blob_content_encoding=content_settings.content_encoding,
|
438
|
-
blob_content_language=content_settings.content_language,
|
439
|
-
blob_content_disposition=content_settings.content_disposition
|
440
|
-
)
|
441
|
-
kwargs['blob_tags_string'] = serialize_blob_tags_header(kwargs.pop('tags', None))
|
442
|
-
kwargs['stream'] = stream
|
443
|
-
kwargs['length'] = length
|
444
|
-
kwargs['overwrite'] = overwrite
|
445
|
-
kwargs['headers'] = headers
|
446
|
-
kwargs['validate_content'] = validate_content
|
447
|
-
kwargs['blob_settings'] = self._config
|
448
|
-
kwargs['max_concurrency'] = max_concurrency
|
449
|
-
kwargs['encryption_options'] = encryption_options
|
450
|
-
# Add feature flag to user agent for encryption
|
451
|
-
if self.key_encryption_key:
|
452
|
-
modify_user_agent_for_encryption(
|
453
|
-
self._config.user_agent_policy.user_agent,
|
454
|
-
self._sdk_moniker,
|
455
|
-
self.encryption_version,
|
456
|
-
kwargs)
|
457
|
-
|
458
|
-
if blob_type == BlobType.BlockBlob:
|
459
|
-
kwargs['client'] = self._client.block_blob
|
460
|
-
elif blob_type == BlobType.PageBlob:
|
461
|
-
if self.encryption_version == '2.0' and (self.require_encryption or self.key_encryption_key is not None):
|
462
|
-
raise ValueError("Encryption version 2.0 does not currently support page blobs.")
|
463
|
-
kwargs['client'] = self._client.page_blob
|
464
|
-
elif blob_type == BlobType.AppendBlob:
|
465
|
-
if self.require_encryption or (self.key_encryption_key is not None):
|
466
|
-
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
467
|
-
kwargs['client'] = self._client.append_blob
|
468
|
-
else:
|
469
|
-
raise ValueError(f"Unsupported BlobType: {blob_type}")
|
470
|
-
return kwargs
|
471
|
-
|
472
|
-
def _upload_blob_from_url_options(self, source_url, **kwargs):
|
473
|
-
# type: (...) -> Dict[str, Any]
|
474
|
-
tier = kwargs.pop('standard_blob_tier', None)
|
475
|
-
overwrite = kwargs.pop('overwrite', False)
|
476
|
-
content_settings = kwargs.pop('content_settings', None)
|
477
|
-
source_authorization = kwargs.pop('source_authorization', None)
|
478
|
-
if content_settings:
|
479
|
-
kwargs['blob_http_headers'] = BlobHTTPHeaders(
|
480
|
-
blob_cache_control=content_settings.cache_control,
|
481
|
-
blob_content_type=content_settings.content_type,
|
482
|
-
blob_content_md5=None,
|
483
|
-
blob_content_encoding=content_settings.content_encoding,
|
484
|
-
blob_content_language=content_settings.content_language,
|
485
|
-
blob_content_disposition=content_settings.content_disposition
|
486
|
-
)
|
487
|
-
cpk = kwargs.pop('cpk', None)
|
488
|
-
cpk_info = None
|
489
|
-
if cpk:
|
490
|
-
if self.scheme.lower() != 'https':
|
491
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
492
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
493
|
-
encryption_algorithm=cpk.algorithm)
|
494
|
-
|
495
|
-
options = {
|
496
|
-
'copy_source_authorization': source_authorization,
|
497
|
-
'content_length': 0,
|
498
|
-
'copy_source_blob_properties': kwargs.pop('include_source_blob_properties', True),
|
499
|
-
'source_content_md5': kwargs.pop('source_content_md5', None),
|
500
|
-
'copy_source': source_url,
|
501
|
-
'modified_access_conditions': get_modify_conditions(kwargs),
|
502
|
-
'blob_tags_string': serialize_blob_tags_header(kwargs.pop('tags', None)),
|
503
|
-
'cls': return_response_headers,
|
504
|
-
'lease_access_conditions': get_access_conditions(kwargs.pop('destination_lease', None)),
|
505
|
-
'tier': tier.value if tier else None,
|
506
|
-
'source_modified_access_conditions': get_source_conditions(kwargs),
|
507
|
-
'cpk_info': cpk_info,
|
508
|
-
'cpk_scope_info': get_cpk_scope_info(kwargs)
|
509
|
-
}
|
510
|
-
options.update(kwargs)
|
511
|
-
if not overwrite and not _any_conditions(**options): # pylint: disable=protected-access
|
512
|
-
options['modified_access_conditions'].if_none_match = '*'
|
513
|
-
return options
|
514
|
-
|
515
322
|
@distributed_trace
|
516
|
-
def upload_blob_from_url(self, source_url, **kwargs):
|
517
|
-
# type: (str, Any) -> Dict[str, Any]
|
323
|
+
def upload_blob_from_url(self, source_url: str, **kwargs: Any) -> Dict[str, Any]:
|
518
324
|
"""
|
519
325
|
Creates a new Block Blob where the content of the blob is read from a given URL.
|
520
326
|
The content of an existing blob is overwritten with the new blob.
|
@@ -522,9 +328,9 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
522
328
|
:param str source_url:
|
523
329
|
A URL of up to 2 KB in length that specifies a file or blob.
|
524
330
|
The value should be URL-encoded as it would appear in a request URI.
|
525
|
-
|
526
|
-
|
527
|
-
is public, no authentication is required.
|
331
|
+
The source must either be public or must be authenticated via a shared
|
332
|
+
access signature as part of the url or using the source_authorization keyword.
|
333
|
+
If the source is public, no authentication is required.
|
528
334
|
Examples:
|
529
335
|
https://myaccount.blob.core.windows.net/mycontainer/myblob
|
530
336
|
|
@@ -541,7 +347,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
541
347
|
The tag set may contain at most 10 tags. Tag keys must be between 1 and 128 characters,
|
542
348
|
and tag values must be between 0 and 256 characters.
|
543
349
|
Valid tag key and value characters include: lowercase and uppercase letters, digits (0-9),
|
544
|
-
space (
|
350
|
+
space (' '), plus (+), minus (-), period (.), solidus (/), colon (:), equals (=), underscore (_)
|
545
351
|
:paramtype tags: dict(str, str)
|
546
352
|
:keyword bytearray source_content_md5:
|
547
353
|
Specify the md5 that is used to verify the integrity of the source bytes.
|
@@ -589,7 +395,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
589
395
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
590
396
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
591
397
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
592
|
-
#other-client--per-operation-configuration>`
|
398
|
+
#other-client--per-operation-configuration>`__.
|
593
399
|
:keyword ~azure.storage.blob.ContentSettings content_settings:
|
594
400
|
ContentSettings object used to set blob properties. Used to set content type, encoding,
|
595
401
|
language, disposition, md5, and cache control.
|
@@ -609,25 +415,27 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
609
415
|
:keyword str source_authorization:
|
610
416
|
Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is
|
611
417
|
the prefix of the source_authorization string.
|
612
|
-
:returns:
|
418
|
+
:returns: Blob-updated property Dict (Etag and last modified)
|
613
419
|
:rtype: Dict[str, Any]
|
614
420
|
"""
|
615
|
-
|
616
|
-
|
421
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
422
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
423
|
+
options = _upload_blob_from_url_options(
|
424
|
+
source_url=source_url,
|
617
425
|
**kwargs)
|
618
426
|
try:
|
619
|
-
return self._client.block_blob.put_blob_from_url(**options)
|
427
|
+
return cast(Dict[str, Any], self._client.block_blob.put_blob_from_url(**options))
|
620
428
|
except HttpResponseError as error:
|
621
429
|
process_storage_error(error)
|
622
430
|
|
623
431
|
@distributed_trace
|
624
432
|
def upload_blob(
|
625
|
-
|
626
|
-
|
627
|
-
|
628
|
-
|
629
|
-
|
630
|
-
|
433
|
+
self, data: Union[bytes, str, Iterable[AnyStr], IO[bytes]],
|
434
|
+
blob_type: Union[str, BlobType] = BlobType.BLOCKBLOB,
|
435
|
+
length: Optional[int] = None,
|
436
|
+
metadata: Optional[Dict[str, str]] = None,
|
437
|
+
**kwargs: Any
|
438
|
+
) -> Dict[str, Any]:
|
631
439
|
"""Creates a new blob from a data source with automatic chunking.
|
632
440
|
|
633
441
|
:param data: The blob data to upload.
|
@@ -645,7 +453,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
645
453
|
The tag set may contain at most 10 tags. Tag keys must be between 1 and 128 characters,
|
646
454
|
and tag values must be between 0 and 256 characters.
|
647
455
|
Valid tag key and value characters include: lowercase and uppercase letters, digits (0-9),
|
648
|
-
space (
|
456
|
+
space (' '), plus (+), minus (-), period (.), solidus (/), colon (:), equals (=), underscore (_)
|
649
457
|
|
650
458
|
.. versionadded:: 12.4.0
|
651
459
|
|
@@ -751,10 +559,10 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
751
559
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
752
560
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
753
561
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
754
|
-
#other-client--per-operation-configuration>`
|
562
|
+
#other-client--per-operation-configuration>`__. This method may make multiple calls to the service and
|
755
563
|
the timeout will apply to each call individually.
|
756
|
-
:returns: Blob-updated property
|
757
|
-
:rtype:
|
564
|
+
:returns: Blob-updated property Dict (Etag and last modified)
|
565
|
+
:rtype: Dict[str, Any]
|
758
566
|
|
759
567
|
.. admonition:: Example:
|
760
568
|
|
@@ -765,11 +573,24 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
765
573
|
:dedent: 12
|
766
574
|
:caption: Upload a blob to the container.
|
767
575
|
"""
|
768
|
-
|
769
|
-
|
576
|
+
if self.require_encryption and not self.key_encryption_key:
|
577
|
+
raise ValueError("Encryption required but no key was provided.")
|
578
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
579
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
580
|
+
options = _upload_blob_options(
|
581
|
+
data=data,
|
770
582
|
blob_type=blob_type,
|
771
583
|
length=length,
|
772
584
|
metadata=metadata,
|
585
|
+
encryption_options={
|
586
|
+
'required': self.require_encryption,
|
587
|
+
'version': self.encryption_version,
|
588
|
+
'key': self.key_encryption_key,
|
589
|
+
'resolver': self.key_resolver_function
|
590
|
+
},
|
591
|
+
config=self._config,
|
592
|
+
sdk_moniker=self._sdk_moniker,
|
593
|
+
client=self._client,
|
773
594
|
**kwargs)
|
774
595
|
if blob_type == BlobType.BlockBlob:
|
775
596
|
return upload_block_blob(**options)
|
@@ -777,84 +598,34 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
777
598
|
return upload_page_blob(**options)
|
778
599
|
return upload_append_blob(**options)
|
779
600
|
|
780
|
-
def _download_blob_options(self, offset=None, length=None, encoding=None, **kwargs):
|
781
|
-
# type: (Optional[int], Optional[int], Optional[str], **Any) -> Dict[str, Any]
|
782
|
-
if self.require_encryption and not (self.key_encryption_key or self.key_resolver_function):
|
783
|
-
raise ValueError("Encryption required but no key was provided.")
|
784
|
-
if length is not None and offset is None:
|
785
|
-
raise ValueError("Offset value must not be None if length is set.")
|
786
|
-
if length is not None:
|
787
|
-
length = offset + length - 1 # Service actually uses an end-range inclusive index
|
788
|
-
|
789
|
-
validate_content = kwargs.pop('validate_content', False)
|
790
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
791
|
-
mod_conditions = get_modify_conditions(kwargs)
|
792
|
-
version_id = get_version_id(self.version_id, kwargs)
|
793
|
-
|
794
|
-
cpk = kwargs.pop('cpk', None)
|
795
|
-
cpk_info = None
|
796
|
-
if cpk:
|
797
|
-
if self.scheme.lower() != 'https':
|
798
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
799
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
800
|
-
encryption_algorithm=cpk.algorithm)
|
801
|
-
|
802
|
-
# Add feature flag to user agent for encryption
|
803
|
-
if self.key_encryption_key or self.key_resolver_function:
|
804
|
-
modify_user_agent_for_encryption(
|
805
|
-
self._config.user_agent_policy.user_agent,
|
806
|
-
self._sdk_moniker,
|
807
|
-
self.encryption_version,
|
808
|
-
kwargs)
|
809
|
-
|
810
|
-
options = {
|
811
|
-
'clients': self._client,
|
812
|
-
'config': self._config,
|
813
|
-
'start_range': offset,
|
814
|
-
'end_range': length,
|
815
|
-
'version_id': version_id,
|
816
|
-
'validate_content': validate_content,
|
817
|
-
'encryption_options': {
|
818
|
-
'required': self.require_encryption,
|
819
|
-
'key': self.key_encryption_key,
|
820
|
-
'resolver': self.key_resolver_function},
|
821
|
-
'lease_access_conditions': access_conditions,
|
822
|
-
'modified_access_conditions': mod_conditions,
|
823
|
-
'cpk_info': cpk_info,
|
824
|
-
'download_cls': kwargs.pop('cls', None) or deserialize_blob_stream,
|
825
|
-
'max_concurrency':kwargs.pop('max_concurrency', 1),
|
826
|
-
'encoding': encoding,
|
827
|
-
'timeout': kwargs.pop('timeout', None),
|
828
|
-
'name': self.blob_name,
|
829
|
-
'container': self.container_name}
|
830
|
-
options.update(kwargs)
|
831
|
-
return options
|
832
|
-
|
833
601
|
@overload
|
834
602
|
def download_blob(
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
603
|
+
self, offset: Optional[int] = None,
|
604
|
+
length: Optional[int] = None,
|
605
|
+
*,
|
606
|
+
encoding: str,
|
607
|
+
**kwargs: Any
|
608
|
+
) -> StorageStreamDownloader[str]:
|
840
609
|
...
|
841
610
|
|
842
611
|
@overload
|
843
612
|
def download_blob(
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
613
|
+
self, offset: Optional[int] = None,
|
614
|
+
length: Optional[int] = None,
|
615
|
+
*,
|
616
|
+
encoding: None = None,
|
617
|
+
**kwargs: Any
|
618
|
+
) -> StorageStreamDownloader[bytes]:
|
849
619
|
...
|
850
620
|
|
851
621
|
@distributed_trace
|
852
622
|
def download_blob(
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
623
|
+
self, offset: Optional[int] = None,
|
624
|
+
length: Optional[int] = None,
|
625
|
+
*,
|
626
|
+
encoding: Union[str, None] = None,
|
627
|
+
**kwargs: Any
|
628
|
+
) -> Union[StorageStreamDownloader[str], StorageStreamDownloader[bytes]]:
|
858
629
|
"""Downloads a blob to the StorageStreamDownloader. The readall() method must
|
859
630
|
be used to read all the content or readinto() must be used to download the blob into
|
860
631
|
a stream. Using chunks() returns an iterator which allows the user to iterate over the content in chunks.
|
@@ -870,6 +641,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
870
641
|
value that, when present, specifies the version of the blob to download.
|
871
642
|
|
872
643
|
.. versionadded:: 12.4.0
|
644
|
+
|
873
645
|
This keyword argument was introduced in API version '2019-12-12'.
|
874
646
|
|
875
647
|
:keyword bool validate_content:
|
@@ -916,7 +688,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
916
688
|
a secure connection must be established to transfer the key.
|
917
689
|
:keyword int max_concurrency:
|
918
690
|
The number of parallel connections with which to download.
|
919
|
-
:keyword str encoding:
|
691
|
+
:keyword Optional[str] encoding:
|
920
692
|
Encoding to decode the downloaded bytes. Default is None, i.e. no decoding.
|
921
693
|
:keyword progress_hook:
|
922
694
|
A callback to track the progress of a long running download. The signature is
|
@@ -928,7 +700,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
928
700
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
929
701
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
930
702
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
931
|
-
#other-client--per-operation-configuration>`
|
703
|
+
#other-client--per-operation-configuration>`__. This method may make multiple calls to the service and
|
932
704
|
the timeout will apply to each call individually.
|
933
705
|
multiple calls to the Azure service and the timeout will apply to
|
934
706
|
each call individually.
|
@@ -944,82 +716,33 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
944
716
|
:dedent: 12
|
945
717
|
:caption: Download a blob.
|
946
718
|
"""
|
947
|
-
|
719
|
+
if self.require_encryption and not (self.key_encryption_key or self.key_resolver_function):
|
720
|
+
raise ValueError("Encryption required but no key was provided.")
|
721
|
+
if length is not None and offset is None:
|
722
|
+
raise ValueError("Offset value must not be None if length is set.")
|
723
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
724
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
725
|
+
options = _download_blob_options(
|
726
|
+
blob_name=self.blob_name,
|
727
|
+
container_name=self.container_name,
|
728
|
+
version_id=get_version_id(self.version_id, kwargs),
|
948
729
|
offset=offset,
|
949
730
|
length=length,
|
950
731
|
encoding=encoding,
|
732
|
+
encryption_options={
|
733
|
+
'required': self.require_encryption,
|
734
|
+
'version': self.encryption_version,
|
735
|
+
'key': self.key_encryption_key,
|
736
|
+
'resolver': self.key_resolver_function
|
737
|
+
},
|
738
|
+
config=self._config,
|
739
|
+
sdk_moniker=self._sdk_moniker,
|
740
|
+
client=self._client,
|
951
741
|
**kwargs)
|
952
742
|
return StorageStreamDownloader(**options)
|
953
743
|
|
954
|
-
def _quick_query_options(self, query_expression,
|
955
|
-
**kwargs):
|
956
|
-
# type: (str, **Any) -> Dict[str, Any]
|
957
|
-
delimiter = '\n'
|
958
|
-
input_format = kwargs.pop('blob_format', None)
|
959
|
-
if input_format == QuickQueryDialect.DelimitedJson:
|
960
|
-
input_format = DelimitedJsonDialect()
|
961
|
-
if input_format == QuickQueryDialect.DelimitedText:
|
962
|
-
input_format = DelimitedTextDialect()
|
963
|
-
input_parquet_format = input_format == "ParquetDialect"
|
964
|
-
if input_format and not input_parquet_format:
|
965
|
-
try:
|
966
|
-
delimiter = input_format.lineterminator
|
967
|
-
except AttributeError:
|
968
|
-
try:
|
969
|
-
delimiter = input_format.delimiter
|
970
|
-
except AttributeError as exc:
|
971
|
-
raise ValueError("The Type of blob_format can only be DelimitedTextDialect or "
|
972
|
-
"DelimitedJsonDialect or ParquetDialect") from exc
|
973
|
-
output_format = kwargs.pop('output_format', None)
|
974
|
-
if output_format == QuickQueryDialect.DelimitedJson:
|
975
|
-
output_format = DelimitedJsonDialect()
|
976
|
-
if output_format == QuickQueryDialect.DelimitedText:
|
977
|
-
output_format = DelimitedTextDialect()
|
978
|
-
if output_format:
|
979
|
-
if output_format == "ParquetDialect":
|
980
|
-
raise ValueError("ParquetDialect is invalid as an output format.")
|
981
|
-
try:
|
982
|
-
delimiter = output_format.lineterminator
|
983
|
-
except AttributeError:
|
984
|
-
try:
|
985
|
-
delimiter = output_format.delimiter
|
986
|
-
except AttributeError:
|
987
|
-
pass
|
988
|
-
else:
|
989
|
-
output_format = input_format if not input_parquet_format else None
|
990
|
-
query_request = QueryRequest(
|
991
|
-
expression=query_expression,
|
992
|
-
input_serialization=serialize_query_format(input_format),
|
993
|
-
output_serialization=serialize_query_format(output_format)
|
994
|
-
)
|
995
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
996
|
-
mod_conditions = get_modify_conditions(kwargs)
|
997
|
-
|
998
|
-
cpk = kwargs.pop('cpk', None)
|
999
|
-
cpk_info = None
|
1000
|
-
if cpk:
|
1001
|
-
if self.scheme.lower() != 'https':
|
1002
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
1003
|
-
cpk_info = CpkInfo(
|
1004
|
-
encryption_key=cpk.key_value,
|
1005
|
-
encryption_key_sha256=cpk.key_hash,
|
1006
|
-
encryption_algorithm=cpk.algorithm
|
1007
|
-
)
|
1008
|
-
options = {
|
1009
|
-
'query_request': query_request,
|
1010
|
-
'lease_access_conditions': access_conditions,
|
1011
|
-
'modified_access_conditions': mod_conditions,
|
1012
|
-
'cpk_info': cpk_info,
|
1013
|
-
'snapshot': self.snapshot,
|
1014
|
-
'timeout': kwargs.pop('timeout', None),
|
1015
|
-
'cls': return_headers_and_deserialized,
|
1016
|
-
}
|
1017
|
-
options.update(kwargs)
|
1018
|
-
return options, delimiter
|
1019
|
-
|
1020
744
|
@distributed_trace
|
1021
|
-
def query_blob(self, query_expression, **kwargs):
|
1022
|
-
# type: (str, **Any) -> BlobQueryReader
|
745
|
+
def query_blob(self, query_expression: str, **kwargs: Any) -> BlobQueryReader:
|
1023
746
|
"""Enables users to select/project on blob/or blob snapshot data by providing simple query expressions.
|
1024
747
|
This operations returns a BlobQueryReader, users need to use readall() or readinto() to get query data.
|
1025
748
|
|
@@ -1046,7 +769,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1046
769
|
This value can be a DelimitedTextDialect or a DelimitedJsonDialect or ArrowDialect.
|
1047
770
|
These dialects can be passed through their respective classes, the QuickQueryDialect enum or as a string
|
1048
771
|
:paramtype output_format: ~azure.storage.blob.DelimitedTextDialect or ~azure.storage.blob.DelimitedJsonDialect
|
1049
|
-
or
|
772
|
+
or List[~azure.storage.blob.ArrowDialect] or ~azure.storage.blob.QuickQueryDialect or str
|
1050
773
|
:keyword lease:
|
1051
774
|
Required if the blob has an active lease. Value can be a BlobLeaseClient object
|
1052
775
|
or the lease ID as a string.
|
@@ -1084,7 +807,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1084
807
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
1085
808
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
1086
809
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
1087
|
-
#other-client--per-operation-configuration>`
|
810
|
+
#other-client--per-operation-configuration>`__.
|
1088
811
|
:returns: A streaming object (BlobQueryReader)
|
1089
812
|
:rtype: ~azure.storage.blob.BlobQueryReader
|
1090
813
|
|
@@ -1100,7 +823,9 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1100
823
|
errors = kwargs.pop("on_error", None)
|
1101
824
|
error_cls = kwargs.pop("error_cls", BlobQueryError)
|
1102
825
|
encoding = kwargs.pop("encoding", None)
|
1103
|
-
|
826
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
827
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
828
|
+
options, delimiter = _quick_query_options(self.snapshot, query_expression, **kwargs)
|
1104
829
|
try:
|
1105
830
|
headers, raw_response_body = self._client.blob.query(**options)
|
1106
831
|
except HttpResponseError as error:
|
@@ -1115,36 +840,8 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1115
840
|
response=raw_response_body,
|
1116
841
|
error_cls=error_cls)
|
1117
842
|
|
1118
|
-
@staticmethod
|
1119
|
-
def _generic_delete_blob_options(delete_snapshots=None, **kwargs):
|
1120
|
-
# type: (str, **Any) -> Dict[str, Any]
|
1121
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
1122
|
-
mod_conditions = get_modify_conditions(kwargs)
|
1123
|
-
if delete_snapshots:
|
1124
|
-
delete_snapshots = DeleteSnapshotsOptionType(delete_snapshots)
|
1125
|
-
options = {
|
1126
|
-
'timeout': kwargs.pop('timeout', None),
|
1127
|
-
'snapshot': kwargs.pop('snapshot', None), # this is added for delete_blobs
|
1128
|
-
'delete_snapshots': delete_snapshots or None,
|
1129
|
-
'lease_access_conditions': access_conditions,
|
1130
|
-
'modified_access_conditions': mod_conditions}
|
1131
|
-
options.update(kwargs)
|
1132
|
-
return options
|
1133
|
-
|
1134
|
-
def _delete_blob_options(self, delete_snapshots=None, **kwargs):
|
1135
|
-
# type: (str, **Any) -> Dict[str, Any]
|
1136
|
-
if self.snapshot and delete_snapshots:
|
1137
|
-
raise ValueError("The delete_snapshots option cannot be used with a specific snapshot.")
|
1138
|
-
version_id = get_version_id(self.version_id, kwargs)
|
1139
|
-
options = self._generic_delete_blob_options(delete_snapshots, **kwargs)
|
1140
|
-
options['snapshot'] = self.snapshot
|
1141
|
-
options['version_id'] = version_id
|
1142
|
-
options['blob_delete_type'] = kwargs.pop('blob_delete_type', None)
|
1143
|
-
return options
|
1144
|
-
|
1145
843
|
@distributed_trace
|
1146
|
-
def delete_blob(self, delete_snapshots=None, **kwargs):
|
1147
|
-
# type: (str, **Any) -> None
|
844
|
+
def delete_blob(self, delete_snapshots: Optional[str] = None, **kwargs: Any) -> None:
|
1148
845
|
"""Marks the specified blob for deletion.
|
1149
846
|
|
1150
847
|
The blob is later deleted during garbage collection.
|
@@ -1158,15 +855,16 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1158
855
|
Soft deleted blob is accessible through :func:`~ContainerClient.list_blobs()` specifying `include=['deleted']`
|
1159
856
|
option. Soft-deleted blob can be restored using :func:`undelete` operation.
|
1160
857
|
|
1161
|
-
:param str delete_snapshots:
|
858
|
+
:param Optional[str] delete_snapshots:
|
1162
859
|
Required if the blob has associated snapshots. Values include:
|
1163
860
|
- "only": Deletes only the blobs snapshots.
|
1164
861
|
- "include": Deletes the blob along with all snapshots.
|
1165
|
-
:keyword str version_id:
|
862
|
+
:keyword Optional[str] version_id:
|
1166
863
|
The version id parameter is an opaque DateTime
|
1167
864
|
value that, when present, specifies the version of the blob to delete.
|
1168
865
|
|
1169
866
|
.. versionadded:: 12.4.0
|
867
|
+
|
1170
868
|
This keyword argument was introduced in API version '2019-12-12'.
|
1171
869
|
|
1172
870
|
:keyword lease:
|
@@ -1202,7 +900,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1202
900
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
1203
901
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
1204
902
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
1205
|
-
#other-client--per-operation-configuration>`
|
903
|
+
#other-client--per-operation-configuration>`__.
|
1206
904
|
:rtype: None
|
1207
905
|
|
1208
906
|
.. admonition:: Example:
|
@@ -1214,15 +912,18 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1214
912
|
:dedent: 12
|
1215
913
|
:caption: Delete a blob.
|
1216
914
|
"""
|
1217
|
-
options =
|
915
|
+
options = _delete_blob_options(
|
916
|
+
snapshot=self.snapshot,
|
917
|
+
version_id=get_version_id(self.version_id, kwargs),
|
918
|
+
delete_snapshots=delete_snapshots,
|
919
|
+
**kwargs)
|
1218
920
|
try:
|
1219
921
|
self._client.blob.delete(**options)
|
1220
922
|
except HttpResponseError as error:
|
1221
923
|
process_storage_error(error)
|
1222
924
|
|
1223
925
|
@distributed_trace
|
1224
|
-
def undelete_blob(self, **kwargs):
|
1225
|
-
# type: (**Any) -> None
|
926
|
+
def undelete_blob(self, **kwargs: Any) -> None:
|
1226
927
|
"""Restores soft-deleted blobs or snapshots.
|
1227
928
|
|
1228
929
|
Operation will only be successful if used within the specified number of days
|
@@ -1237,7 +938,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1237
938
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
1238
939
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
1239
940
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
1240
|
-
#other-client--per-operation-configuration>`
|
941
|
+
#other-client--per-operation-configuration>`__.
|
1241
942
|
:rtype: None
|
1242
943
|
|
1243
944
|
.. admonition:: Example:
|
@@ -1255,8 +956,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1255
956
|
process_storage_error(error)
|
1256
957
|
|
1257
958
|
@distributed_trace
|
1258
|
-
def exists(self, **kwargs):
|
1259
|
-
# type: (**Any) -> bool
|
959
|
+
def exists(self, **kwargs: Any) -> bool:
|
1260
960
|
"""
|
1261
961
|
Returns True if a blob exists with the defined parameters, and returns
|
1262
962
|
False otherwise.
|
@@ -1269,7 +969,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1269
969
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
1270
970
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
1271
971
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
1272
|
-
#other-client--per-operation-configuration>`
|
972
|
+
#other-client--per-operation-configuration>`__.
|
1273
973
|
:returns: boolean
|
1274
974
|
:rtype: bool
|
1275
975
|
"""
|
@@ -1290,8 +990,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1290
990
|
return False
|
1291
991
|
|
1292
992
|
@distributed_trace
|
1293
|
-
def get_blob_properties(self, **kwargs):
|
1294
|
-
# type: (**Any) -> BlobProperties
|
993
|
+
def get_blob_properties(self, **kwargs: Any) -> BlobProperties:
|
1295
994
|
"""Returns all user-defined metadata, standard HTTP properties, and
|
1296
995
|
system properties for the blob. It does not return the content of the blob.
|
1297
996
|
|
@@ -1304,6 +1003,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1304
1003
|
value that, when present, specifies the version of the blob to get properties.
|
1305
1004
|
|
1306
1005
|
.. versionadded:: 12.4.0
|
1006
|
+
|
1307
1007
|
This keyword argument was introduced in API version '2019-12-12'.
|
1308
1008
|
|
1309
1009
|
:keyword ~datetime.datetime if_modified_since:
|
@@ -1339,7 +1039,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1339
1039
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
1340
1040
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
1341
1041
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
1342
|
-
#other-client--per-operation-configuration>`
|
1042
|
+
#other-client--per-operation-configuration>`__.
|
1343
1043
|
:returns: BlobProperties
|
1344
1044
|
:rtype: ~azure.storage.blob.BlobProperties
|
1345
1045
|
|
@@ -1367,7 +1067,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1367
1067
|
cls_method = kwargs.pop('cls', None)
|
1368
1068
|
if cls_method:
|
1369
1069
|
kwargs['cls'] = partial(deserialize_pipeline_response_into_cls, cls_method)
|
1370
|
-
blob_props = self._client.blob.get_properties(
|
1070
|
+
blob_props = cast(BlobProperties, self._client.blob.get_properties(
|
1371
1071
|
timeout=kwargs.pop('timeout', None),
|
1372
1072
|
version_id=version_id,
|
1373
1073
|
snapshot=self.snapshot,
|
@@ -1375,41 +1075,17 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1375
1075
|
modified_access_conditions=mod_conditions,
|
1376
1076
|
cls=kwargs.pop('cls', None) or deserialize_blob_properties,
|
1377
1077
|
cpk_info=cpk_info,
|
1378
|
-
**kwargs)
|
1078
|
+
**kwargs))
|
1379
1079
|
except HttpResponseError as error:
|
1380
1080
|
process_storage_error(error)
|
1381
1081
|
blob_props.name = self.blob_name
|
1382
1082
|
if isinstance(blob_props, BlobProperties):
|
1383
1083
|
blob_props.container = self.container_name
|
1384
1084
|
blob_props.snapshot = self.snapshot
|
1385
|
-
return blob_props
|
1386
|
-
|
1387
|
-
def _set_http_headers_options(self, content_settings=None, **kwargs):
|
1388
|
-
# type: (Optional[ContentSettings], **Any) -> Dict[str, Any]
|
1389
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
1390
|
-
mod_conditions = get_modify_conditions(kwargs)
|
1391
|
-
blob_headers = None
|
1392
|
-
if content_settings:
|
1393
|
-
blob_headers = BlobHTTPHeaders(
|
1394
|
-
blob_cache_control=content_settings.cache_control,
|
1395
|
-
blob_content_type=content_settings.content_type,
|
1396
|
-
blob_content_md5=content_settings.content_md5,
|
1397
|
-
blob_content_encoding=content_settings.content_encoding,
|
1398
|
-
blob_content_language=content_settings.content_language,
|
1399
|
-
blob_content_disposition=content_settings.content_disposition
|
1400
|
-
)
|
1401
|
-
options = {
|
1402
|
-
'timeout': kwargs.pop('timeout', None),
|
1403
|
-
'blob_http_headers': blob_headers,
|
1404
|
-
'lease_access_conditions': access_conditions,
|
1405
|
-
'modified_access_conditions': mod_conditions,
|
1406
|
-
'cls': return_response_headers}
|
1407
|
-
options.update(kwargs)
|
1408
|
-
return options
|
1085
|
+
return blob_props
|
1409
1086
|
|
1410
1087
|
@distributed_trace
|
1411
|
-
def set_http_headers(self, content_settings=None, **kwargs):
|
1412
|
-
# type: (Optional[ContentSettings], **Any) -> None
|
1088
|
+
def set_http_headers(self, content_settings: Optional["ContentSettings"] = None, **kwargs: Any) -> Dict[str, Any]:
|
1413
1089
|
"""Sets system properties on the blob.
|
1414
1090
|
|
1415
1091
|
If one property is set for the content_settings, all properties will be overridden.
|
@@ -1449,45 +1125,21 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1449
1125
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
1450
1126
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
1451
1127
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
1452
|
-
#other-client--per-operation-configuration>`
|
1128
|
+
#other-client--per-operation-configuration>`__.
|
1453
1129
|
:returns: Blob-updated property dict (Etag and last modified)
|
1454
1130
|
:rtype: Dict[str, Any]
|
1455
1131
|
"""
|
1456
|
-
options =
|
1132
|
+
options = _set_http_headers_options(content_settings=content_settings, **kwargs)
|
1457
1133
|
try:
|
1458
|
-
return self._client.blob.set_http_headers(**options)
|
1134
|
+
return cast(Dict[str, Any], self._client.blob.set_http_headers(**options))
|
1459
1135
|
except HttpResponseError as error:
|
1460
1136
|
process_storage_error(error)
|
1461
1137
|
|
1462
|
-
def _set_blob_metadata_options(self, metadata=None, **kwargs):
|
1463
|
-
# type: (Optional[Dict[str, str]], **Any) -> Dict[str, Any]
|
1464
|
-
headers = kwargs.pop('headers', {})
|
1465
|
-
headers.update(add_metadata_headers(metadata))
|
1466
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
1467
|
-
mod_conditions = get_modify_conditions(kwargs)
|
1468
|
-
cpk_scope_info = get_cpk_scope_info(kwargs)
|
1469
|
-
|
1470
|
-
cpk = kwargs.pop('cpk', None)
|
1471
|
-
cpk_info = None
|
1472
|
-
if cpk:
|
1473
|
-
if self.scheme.lower() != 'https':
|
1474
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
1475
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
1476
|
-
encryption_algorithm=cpk.algorithm)
|
1477
|
-
options = {
|
1478
|
-
'timeout': kwargs.pop('timeout', None),
|
1479
|
-
'lease_access_conditions': access_conditions,
|
1480
|
-
'modified_access_conditions': mod_conditions,
|
1481
|
-
'cpk_scope_info': cpk_scope_info,
|
1482
|
-
'cpk_info': cpk_info,
|
1483
|
-
'cls': return_response_headers,
|
1484
|
-
'headers': headers}
|
1485
|
-
options.update(kwargs)
|
1486
|
-
return options
|
1487
|
-
|
1488
1138
|
@distributed_trace
|
1489
|
-
def set_blob_metadata(
|
1490
|
-
|
1139
|
+
def set_blob_metadata(
|
1140
|
+
self, metadata: Optional[Dict[str, str]] = None,
|
1141
|
+
**kwargs: Any
|
1142
|
+
) -> Dict[str, Union[str, datetime]]:
|
1491
1143
|
"""Sets user-defined metadata for the blob as one or more name-value pairs.
|
1492
1144
|
|
1493
1145
|
:param metadata:
|
@@ -1540,19 +1192,23 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1540
1192
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
1541
1193
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
1542
1194
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
1543
|
-
#other-client--per-operation-configuration>`
|
1195
|
+
#other-client--per-operation-configuration>`__.
|
1544
1196
|
:returns: Blob-updated property dict (Etag and last modified)
|
1545
1197
|
:rtype: Dict[str, Union[str, datetime]]
|
1546
1198
|
"""
|
1547
|
-
|
1199
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
1200
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
1201
|
+
options = _set_blob_metadata_options(metadata=metadata, **kwargs)
|
1548
1202
|
try:
|
1549
|
-
return self._client.blob.set_metadata(**options)
|
1203
|
+
return cast(Dict[str, Union[str, datetime]], self._client.blob.set_metadata(**options))
|
1550
1204
|
except HttpResponseError as error:
|
1551
1205
|
process_storage_error(error)
|
1552
1206
|
|
1553
1207
|
@distributed_trace
|
1554
|
-
def set_immutability_policy(
|
1555
|
-
|
1208
|
+
def set_immutability_policy(
|
1209
|
+
self, immutability_policy: "ImmutabilityPolicy",
|
1210
|
+
**kwargs: Any
|
1211
|
+
) -> Dict[str, str]:
|
1556
1212
|
"""The Set Immutability Policy operation sets the immutability policy on the blob.
|
1557
1213
|
|
1558
1214
|
.. versionadded:: 12.10.0
|
@@ -1569,18 +1225,17 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1569
1225
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
1570
1226
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
1571
1227
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
1572
|
-
#other-client--per-operation-configuration>`
|
1228
|
+
#other-client--per-operation-configuration>`__.
|
1573
1229
|
:returns: Key value pairs of blob tags.
|
1574
1230
|
:rtype: Dict[str, str]
|
1575
1231
|
"""
|
1576
1232
|
|
1577
1233
|
kwargs['immutability_policy_expiry'] = immutability_policy.expiry_time
|
1578
1234
|
kwargs['immutability_policy_mode'] = immutability_policy.policy_mode
|
1579
|
-
return self._client.blob.set_immutability_policy(cls=return_response_headers, **kwargs)
|
1235
|
+
return cast(Dict[str, str], self._client.blob.set_immutability_policy(cls=return_response_headers, **kwargs))
|
1580
1236
|
|
1581
1237
|
@distributed_trace
|
1582
|
-
def delete_immutability_policy(self, **kwargs):
|
1583
|
-
# type: (**Any) -> None
|
1238
|
+
def delete_immutability_policy(self, **kwargs: Any) -> None:
|
1584
1239
|
"""The Delete Immutability Policy operation deletes the immutability policy on the blob.
|
1585
1240
|
|
1586
1241
|
.. versionadded:: 12.10.0
|
@@ -1591,7 +1246,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1591
1246
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
1592
1247
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
1593
1248
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
1594
|
-
#other-client--per-operation-configuration>`
|
1249
|
+
#other-client--per-operation-configuration>`__.
|
1595
1250
|
:returns: Key value pairs of blob tags.
|
1596
1251
|
:rtype: Dict[str, str]
|
1597
1252
|
"""
|
@@ -1599,8 +1254,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1599
1254
|
self._client.blob.delete_immutability_policy(**kwargs)
|
1600
1255
|
|
1601
1256
|
@distributed_trace
|
1602
|
-
def set_legal_hold(self, legal_hold, **kwargs):
|
1603
|
-
# type: (bool, **Any) -> Dict[str, Union[str, datetime, bool]]
|
1257
|
+
def set_legal_hold(self, legal_hold: bool, **kwargs: Any) -> Dict[str, Union[str, datetime, bool]]:
|
1604
1258
|
"""The Set Legal Hold operation sets a legal hold on the blob.
|
1605
1259
|
|
1606
1260
|
.. versionadded:: 12.10.0
|
@@ -1613,88 +1267,22 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1613
1267
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
1614
1268
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
1615
1269
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
1616
|
-
#other-client--per-operation-configuration>`
|
1270
|
+
#other-client--per-operation-configuration>`__.
|
1617
1271
|
:returns: Key value pairs of blob tags.
|
1618
1272
|
:rtype: Dict[str, Union[str, datetime, bool]]
|
1619
1273
|
"""
|
1620
1274
|
|
1621
|
-
return
|
1622
|
-
|
1623
|
-
def _create_page_blob_options( # type: ignore
|
1624
|
-
self, size, # type: int
|
1625
|
-
content_settings=None, # type: Optional[ContentSettings]
|
1626
|
-
metadata=None, # type: Optional[Dict[str, str]]
|
1627
|
-
premium_page_blob_tier=None, # type: Optional[Union[str, PremiumPageBlobTier]]
|
1628
|
-
**kwargs
|
1629
|
-
):
|
1630
|
-
# type: (...) -> Dict[str, Any]
|
1631
|
-
if self.require_encryption or (self.key_encryption_key is not None):
|
1632
|
-
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
1633
|
-
headers = kwargs.pop('headers', {})
|
1634
|
-
headers.update(add_metadata_headers(metadata))
|
1635
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
1636
|
-
mod_conditions = get_modify_conditions(kwargs)
|
1637
|
-
cpk_scope_info = get_cpk_scope_info(kwargs)
|
1638
|
-
blob_headers = None
|
1639
|
-
if content_settings:
|
1640
|
-
blob_headers = BlobHTTPHeaders(
|
1641
|
-
blob_cache_control=content_settings.cache_control,
|
1642
|
-
blob_content_type=content_settings.content_type,
|
1643
|
-
blob_content_md5=content_settings.content_md5,
|
1644
|
-
blob_content_encoding=content_settings.content_encoding,
|
1645
|
-
blob_content_language=content_settings.content_language,
|
1646
|
-
blob_content_disposition=content_settings.content_disposition
|
1647
|
-
)
|
1648
|
-
|
1649
|
-
sequence_number = kwargs.pop('sequence_number', None)
|
1650
|
-
cpk = kwargs.pop('cpk', None)
|
1651
|
-
cpk_info = None
|
1652
|
-
if cpk:
|
1653
|
-
if self.scheme.lower() != 'https':
|
1654
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
1655
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
1656
|
-
encryption_algorithm=cpk.algorithm)
|
1657
|
-
|
1658
|
-
immutability_policy = kwargs.pop('immutability_policy', None)
|
1659
|
-
if immutability_policy:
|
1660
|
-
kwargs['immutability_policy_expiry'] = immutability_policy.expiry_time
|
1661
|
-
kwargs['immutability_policy_mode'] = immutability_policy.policy_mode
|
1662
|
-
|
1663
|
-
tier = None
|
1664
|
-
if premium_page_blob_tier:
|
1665
|
-
try:
|
1666
|
-
tier = premium_page_blob_tier.value # type: ignore
|
1667
|
-
except AttributeError:
|
1668
|
-
tier = premium_page_blob_tier # type: ignore
|
1669
|
-
|
1670
|
-
blob_tags_string = serialize_blob_tags_header(kwargs.pop('tags', None))
|
1671
|
-
|
1672
|
-
options = {
|
1673
|
-
'content_length': 0,
|
1674
|
-
'blob_content_length': size,
|
1675
|
-
'blob_sequence_number': sequence_number,
|
1676
|
-
'blob_http_headers': blob_headers,
|
1677
|
-
'timeout': kwargs.pop('timeout', None),
|
1678
|
-
'lease_access_conditions': access_conditions,
|
1679
|
-
'modified_access_conditions': mod_conditions,
|
1680
|
-
'cpk_scope_info': cpk_scope_info,
|
1681
|
-
'cpk_info': cpk_info,
|
1682
|
-
'blob_tags_string': blob_tags_string,
|
1683
|
-
'cls': return_response_headers,
|
1684
|
-
"tier": tier,
|
1685
|
-
'headers': headers}
|
1686
|
-
options.update(kwargs)
|
1687
|
-
return options
|
1275
|
+
return cast(Dict[str, Union[str, datetime, bool]],
|
1276
|
+
self._client.blob.set_legal_hold(legal_hold, cls=return_response_headers, **kwargs))
|
1688
1277
|
|
1689
1278
|
@distributed_trace
|
1690
|
-
def create_page_blob(
|
1691
|
-
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1697
|
-
# type: (...) -> Dict[str, Union[str, datetime]]
|
1279
|
+
def create_page_blob(
|
1280
|
+
self, size: int,
|
1281
|
+
content_settings: Optional["ContentSettings"] = None,
|
1282
|
+
metadata: Optional[Dict[str, str]] = None,
|
1283
|
+
premium_page_blob_tier: Optional[Union[str, "PremiumPageBlobTier"]] = None,
|
1284
|
+
**kwargs: Any
|
1285
|
+
) -> Dict[str, Union[str, datetime]]:
|
1698
1286
|
"""Creates a new Page Blob of the specified size.
|
1699
1287
|
|
1700
1288
|
:param int size:
|
@@ -1715,7 +1303,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1715
1303
|
The tag set may contain at most 10 tags. Tag keys must be between 1 and 128 characters,
|
1716
1304
|
and tag values must be between 0 and 256 characters.
|
1717
1305
|
Valid tag key and value characters include: lowercase and uppercase letters, digits (0-9),
|
1718
|
-
space (
|
1306
|
+
space (' '), plus (+), minus (-), period (.), solidus (/), colon (:), equals (=), underscore (_)
|
1719
1307
|
|
1720
1308
|
.. versionadded:: 12.4.0
|
1721
1309
|
|
@@ -1775,73 +1363,31 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1775
1363
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
1776
1364
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
1777
1365
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
1778
|
-
#other-client--per-operation-configuration>`
|
1366
|
+
#other-client--per-operation-configuration>`__.
|
1779
1367
|
:returns: Blob-updated property dict (Etag and last modified).
|
1780
1368
|
:rtype: dict[str, Any]
|
1781
1369
|
"""
|
1782
|
-
|
1783
|
-
|
1370
|
+
if self.require_encryption or (self.key_encryption_key is not None):
|
1371
|
+
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
1372
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
1373
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
1374
|
+
options = _create_page_blob_options(
|
1375
|
+
size=size,
|
1784
1376
|
content_settings=content_settings,
|
1785
1377
|
metadata=metadata,
|
1786
1378
|
premium_page_blob_tier=premium_page_blob_tier,
|
1787
1379
|
**kwargs)
|
1788
1380
|
try:
|
1789
|
-
return self._client.page_blob.create(**options)
|
1381
|
+
return cast(Dict[str, Any], self._client.page_blob.create(**options))
|
1790
1382
|
except HttpResponseError as error:
|
1791
1383
|
process_storage_error(error)
|
1792
1384
|
|
1793
|
-
def _create_append_blob_options(self, content_settings=None, metadata=None, **kwargs):
|
1794
|
-
# type: (Optional[ContentSettings], Optional[Dict[str, str]], **Any) -> Dict[str, Any]
|
1795
|
-
if self.require_encryption or (self.key_encryption_key is not None):
|
1796
|
-
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
1797
|
-
headers = kwargs.pop('headers', {})
|
1798
|
-
headers.update(add_metadata_headers(metadata))
|
1799
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
1800
|
-
mod_conditions = get_modify_conditions(kwargs)
|
1801
|
-
cpk_scope_info = get_cpk_scope_info(kwargs)
|
1802
|
-
blob_headers = None
|
1803
|
-
if content_settings:
|
1804
|
-
blob_headers = BlobHTTPHeaders(
|
1805
|
-
blob_cache_control=content_settings.cache_control,
|
1806
|
-
blob_content_type=content_settings.content_type,
|
1807
|
-
blob_content_md5=content_settings.content_md5,
|
1808
|
-
blob_content_encoding=content_settings.content_encoding,
|
1809
|
-
blob_content_language=content_settings.content_language,
|
1810
|
-
blob_content_disposition=content_settings.content_disposition
|
1811
|
-
)
|
1812
|
-
|
1813
|
-
cpk = kwargs.pop('cpk', None)
|
1814
|
-
cpk_info = None
|
1815
|
-
if cpk:
|
1816
|
-
if self.scheme.lower() != 'https':
|
1817
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
1818
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
1819
|
-
encryption_algorithm=cpk.algorithm)
|
1820
|
-
|
1821
|
-
immutability_policy = kwargs.pop('immutability_policy', None)
|
1822
|
-
if immutability_policy:
|
1823
|
-
kwargs['immutability_policy_expiry'] = immutability_policy.expiry_time
|
1824
|
-
kwargs['immutability_policy_mode'] = immutability_policy.policy_mode
|
1825
|
-
|
1826
|
-
blob_tags_string = serialize_blob_tags_header(kwargs.pop('tags', None))
|
1827
|
-
|
1828
|
-
options = {
|
1829
|
-
'content_length': 0,
|
1830
|
-
'blob_http_headers': blob_headers,
|
1831
|
-
'timeout': kwargs.pop('timeout', None),
|
1832
|
-
'lease_access_conditions': access_conditions,
|
1833
|
-
'modified_access_conditions': mod_conditions,
|
1834
|
-
'cpk_scope_info': cpk_scope_info,
|
1835
|
-
'cpk_info': cpk_info,
|
1836
|
-
'blob_tags_string': blob_tags_string,
|
1837
|
-
'cls': return_response_headers,
|
1838
|
-
'headers': headers}
|
1839
|
-
options.update(kwargs)
|
1840
|
-
return options
|
1841
|
-
|
1842
1385
|
@distributed_trace
|
1843
|
-
def create_append_blob(
|
1844
|
-
|
1386
|
+
def create_append_blob(
|
1387
|
+
self, content_settings: Optional["ContentSettings"] = None,
|
1388
|
+
metadata: Optional[Dict[str, str]] = None,
|
1389
|
+
**kwargs: Any
|
1390
|
+
) -> Dict[str, Union[str, datetime]]:
|
1845
1391
|
"""Creates a new Append Blob. This operation creates a new 0-length append blob. The content
|
1846
1392
|
of any existing blob is overwritten with the newly initialized append blob. To add content to
|
1847
1393
|
the append blob, call the :func:`append_block` or :func:`append_block_from_url` method.
|
@@ -1857,7 +1403,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1857
1403
|
The tag set may contain at most 10 tags. Tag keys must be between 1 and 128 characters,
|
1858
1404
|
and tag values must be between 0 and 256 characters.
|
1859
1405
|
Valid tag key and value characters include: lowercase and uppercase letters, digits (0-9),
|
1860
|
-
space (
|
1406
|
+
space (' '), plus (+), minus (-), period (.), solidus (/), colon (:), equals (=), underscore (_)
|
1861
1407
|
|
1862
1408
|
.. versionadded:: 12.4.0
|
1863
1409
|
|
@@ -1913,48 +1459,28 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
1913
1459
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
1914
1460
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
1915
1461
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
1916
|
-
#other-client--per-operation-configuration>`
|
1462
|
+
#other-client--per-operation-configuration>`__.
|
1917
1463
|
:returns: Blob-updated property dict (Etag and last modified).
|
1918
1464
|
:rtype: dict[str, Any]
|
1919
1465
|
"""
|
1920
|
-
|
1466
|
+
if self.require_encryption or (self.key_encryption_key is not None):
|
1467
|
+
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
1468
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
1469
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
1470
|
+
options = _create_append_blob_options(
|
1921
1471
|
content_settings=content_settings,
|
1922
1472
|
metadata=metadata,
|
1923
1473
|
**kwargs)
|
1924
1474
|
try:
|
1925
|
-
return self._client.append_blob.create(**options)
|
1475
|
+
return cast(Dict[str, Union[str, datetime]], self._client.append_blob.create(**options))
|
1926
1476
|
except HttpResponseError as error:
|
1927
1477
|
process_storage_error(error)
|
1928
1478
|
|
1929
|
-
def _create_snapshot_options(self, metadata=None, **kwargs):
|
1930
|
-
# type: (Optional[Dict[str, str]], **Any) -> Dict[str, Any]
|
1931
|
-
headers = kwargs.pop('headers', {})
|
1932
|
-
headers.update(add_metadata_headers(metadata))
|
1933
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
1934
|
-
mod_conditions = get_modify_conditions(kwargs)
|
1935
|
-
cpk_scope_info = get_cpk_scope_info(kwargs)
|
1936
|
-
cpk = kwargs.pop('cpk', None)
|
1937
|
-
cpk_info = None
|
1938
|
-
if cpk:
|
1939
|
-
if self.scheme.lower() != 'https':
|
1940
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
1941
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
1942
|
-
encryption_algorithm=cpk.algorithm)
|
1943
|
-
|
1944
|
-
options = {
|
1945
|
-
'timeout': kwargs.pop('timeout', None),
|
1946
|
-
'lease_access_conditions': access_conditions,
|
1947
|
-
'modified_access_conditions': mod_conditions,
|
1948
|
-
'cpk_scope_info': cpk_scope_info,
|
1949
|
-
'cpk_info': cpk_info,
|
1950
|
-
'cls': return_response_headers,
|
1951
|
-
'headers': headers}
|
1952
|
-
options.update(kwargs)
|
1953
|
-
return options
|
1954
|
-
|
1955
1479
|
@distributed_trace
|
1956
|
-
def create_snapshot(
|
1957
|
-
|
1480
|
+
def create_snapshot(
|
1481
|
+
self, metadata: Optional[Dict[str, str]] = None,
|
1482
|
+
**kwargs: Any
|
1483
|
+
) -> Dict[str, Union[str, datetime]]:
|
1958
1484
|
"""Creates a snapshot of the blob.
|
1959
1485
|
|
1960
1486
|
A snapshot is a read-only version of a blob that's taken at a point in time.
|
@@ -2012,7 +1538,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2012
1538
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
2013
1539
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
2014
1540
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
2015
|
-
#other-client--per-operation-configuration>`
|
1541
|
+
#other-client--per-operation-configuration>`__.
|
2016
1542
|
:returns: Blob-updated property dict (Snapshot ID, Etag, and last modified).
|
2017
1543
|
:rtype: dict[str, Any]
|
2018
1544
|
|
@@ -2025,92 +1551,21 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2025
1551
|
:dedent: 8
|
2026
1552
|
:caption: Create a snapshot of the blob.
|
2027
1553
|
"""
|
2028
|
-
|
1554
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
1555
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
1556
|
+
options = _create_snapshot_options(metadata=metadata, **kwargs)
|
2029
1557
|
try:
|
2030
|
-
return self._client.blob.create_snapshot(**options)
|
1558
|
+
return cast(Dict[str, Any], self._client.blob.create_snapshot(**options))
|
2031
1559
|
except HttpResponseError as error:
|
2032
1560
|
process_storage_error(error)
|
2033
1561
|
|
2034
|
-
def _start_copy_from_url_options(self, source_url, metadata=None, incremental_copy=False, **kwargs):
|
2035
|
-
# type: (str, Optional[Dict[str, str]], bool, **Any) -> Dict[str, Any]
|
2036
|
-
headers = kwargs.pop('headers', {})
|
2037
|
-
headers.update(add_metadata_headers(metadata))
|
2038
|
-
if 'source_lease' in kwargs:
|
2039
|
-
source_lease = kwargs.pop('source_lease')
|
2040
|
-
try:
|
2041
|
-
headers['x-ms-source-lease-id'] = source_lease.id
|
2042
|
-
except AttributeError:
|
2043
|
-
headers['x-ms-source-lease-id'] = source_lease
|
2044
|
-
|
2045
|
-
tier = kwargs.pop('premium_page_blob_tier', None) or kwargs.pop('standard_blob_tier', None)
|
2046
|
-
tags = kwargs.pop('tags', None)
|
2047
|
-
|
2048
|
-
# Options only available for sync copy
|
2049
|
-
requires_sync = kwargs.pop('requires_sync', None)
|
2050
|
-
encryption_scope_str = kwargs.pop('encryption_scope', None)
|
2051
|
-
source_authorization = kwargs.pop('source_authorization', None)
|
2052
|
-
# If tags is a str, interpret that as copy_source_tags
|
2053
|
-
copy_source_tags = isinstance(tags, str)
|
2054
|
-
|
2055
|
-
if incremental_copy:
|
2056
|
-
if source_authorization:
|
2057
|
-
raise ValueError("Source authorization tokens are not applicable for incremental copying.")
|
2058
|
-
if copy_source_tags:
|
2059
|
-
raise ValueError("Copying source tags is not applicable for incremental copying.")
|
2060
|
-
|
2061
|
-
# TODO: refactor start_copy_from_url api in _blob_client.py. Call _generated/_blob_operations.py copy_from_url
|
2062
|
-
# when requires_sync=True is set.
|
2063
|
-
# Currently both sync copy and async copy are calling _generated/_blob_operations.py start_copy_from_url.
|
2064
|
-
# As sync copy diverges more from async copy, more problem will surface.
|
2065
|
-
if requires_sync is True:
|
2066
|
-
headers['x-ms-requires-sync'] = str(requires_sync)
|
2067
|
-
if encryption_scope_str:
|
2068
|
-
headers['x-ms-encryption-scope'] = encryption_scope_str
|
2069
|
-
if source_authorization:
|
2070
|
-
headers['x-ms-copy-source-authorization'] = source_authorization
|
2071
|
-
if copy_source_tags:
|
2072
|
-
headers['x-ms-copy-source-tag-option'] = tags
|
2073
|
-
else:
|
2074
|
-
if encryption_scope_str:
|
2075
|
-
raise ValueError(
|
2076
|
-
"Encryption_scope is only supported for sync copy, please specify requires_sync=True")
|
2077
|
-
if source_authorization:
|
2078
|
-
raise ValueError(
|
2079
|
-
"Source authorization tokens are only supported for sync copy, please specify requires_sync=True")
|
2080
|
-
if copy_source_tags:
|
2081
|
-
raise ValueError(
|
2082
|
-
"Copying source tags is only supported for sync copy, please specify requires_sync=True")
|
2083
|
-
|
2084
|
-
timeout = kwargs.pop('timeout', None)
|
2085
|
-
dest_mod_conditions = get_modify_conditions(kwargs)
|
2086
|
-
blob_tags_string = serialize_blob_tags_header(tags) if not copy_source_tags else None
|
2087
|
-
|
2088
|
-
immutability_policy = kwargs.pop('immutability_policy', None)
|
2089
|
-
if immutability_policy:
|
2090
|
-
kwargs['immutability_policy_expiry'] = immutability_policy.expiry_time
|
2091
|
-
kwargs['immutability_policy_mode'] = immutability_policy.policy_mode
|
2092
|
-
|
2093
|
-
options = {
|
2094
|
-
'copy_source': source_url,
|
2095
|
-
'seal_blob': kwargs.pop('seal_destination_blob', None),
|
2096
|
-
'timeout': timeout,
|
2097
|
-
'modified_access_conditions': dest_mod_conditions,
|
2098
|
-
'blob_tags_string': blob_tags_string,
|
2099
|
-
'headers': headers,
|
2100
|
-
'cls': return_response_headers,
|
2101
|
-
}
|
2102
|
-
if not incremental_copy:
|
2103
|
-
source_mod_conditions = get_source_conditions(kwargs)
|
2104
|
-
dest_access_conditions = get_access_conditions(kwargs.pop('destination_lease', None))
|
2105
|
-
options['source_modified_access_conditions'] = source_mod_conditions
|
2106
|
-
options['lease_access_conditions'] = dest_access_conditions
|
2107
|
-
options['tier'] = tier.value if tier else None
|
2108
|
-
options.update(kwargs)
|
2109
|
-
return options
|
2110
|
-
|
2111
1562
|
@distributed_trace
|
2112
|
-
def start_copy_from_url(
|
2113
|
-
|
1563
|
+
def start_copy_from_url(
|
1564
|
+
self, source_url: str,
|
1565
|
+
metadata: Optional[Dict[str, str]] = None,
|
1566
|
+
incremental_copy: bool = False,
|
1567
|
+
**kwargs: Any
|
1568
|
+
) -> Dict[str, Union[str, datetime]]:
|
2114
1569
|
"""Copies a blob from the given URL.
|
2115
1570
|
|
2116
1571
|
This operation returns a dictionary containing `copy_status` and `copy_id`,
|
@@ -2171,7 +1626,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2171
1626
|
The tag set may contain at most 10 tags. Tag keys must be between 1 and 128 characters,
|
2172
1627
|
and tag values must be between 0 and 256 characters.
|
2173
1628
|
Valid tag key and value characters include: lowercase and uppercase letters, digits (0-9),
|
2174
|
-
space (
|
1629
|
+
space (' '), plus (+), minus (-), period (.), solidus (/), colon (:), equals (=), underscore (_).
|
2175
1630
|
|
2176
1631
|
The (case-sensitive) literal "COPY" can instead be passed to copy tags from the source blob.
|
2177
1632
|
This option is only available when `incremental_copy=False` and `requires_sync=True`.
|
@@ -2243,7 +1698,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2243
1698
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
2244
1699
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
2245
1700
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
2246
|
-
#other-client--per-operation-configuration>`
|
1701
|
+
#other-client--per-operation-configuration>`__.
|
2247
1702
|
:keyword ~azure.storage.blob.PremiumPageBlobTier premium_page_blob_tier:
|
2248
1703
|
A page blob tier value to set the blob to. The tier correlates to the size of the
|
2249
1704
|
blob and number of allowed IOPS. This is only applicable to page blobs on
|
@@ -2287,38 +1742,23 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2287
1742
|
:dedent: 12
|
2288
1743
|
:caption: Copy a blob from a URL.
|
2289
1744
|
"""
|
2290
|
-
options =
|
2291
|
-
source_url=
|
1745
|
+
options = _start_copy_from_url_options(
|
1746
|
+
source_url=source_url,
|
2292
1747
|
metadata=metadata,
|
2293
1748
|
incremental_copy=incremental_copy,
|
2294
1749
|
**kwargs)
|
2295
1750
|
try:
|
2296
1751
|
if incremental_copy:
|
2297
|
-
return self._client.page_blob.copy_incremental(**options)
|
2298
|
-
return self._client.blob.start_copy_from_url(**options)
|
1752
|
+
return cast(Dict[str, Union[str, datetime]], self._client.page_blob.copy_incremental(**options))
|
1753
|
+
return cast(Dict[str, Union[str, datetime]], self._client.blob.start_copy_from_url(**options))
|
2299
1754
|
except HttpResponseError as error:
|
2300
1755
|
process_storage_error(error)
|
2301
1756
|
|
2302
|
-
def _abort_copy_options(self, copy_id, **kwargs):
|
2303
|
-
# type: (Union[str, Dict[str, Any], BlobProperties], **Any) -> Dict[str, Any]
|
2304
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
2305
|
-
try:
|
2306
|
-
copy_id = copy_id.copy.id
|
2307
|
-
except AttributeError:
|
2308
|
-
try:
|
2309
|
-
copy_id = copy_id['copy_id']
|
2310
|
-
except TypeError:
|
2311
|
-
pass
|
2312
|
-
options = {
|
2313
|
-
'copy_id': copy_id,
|
2314
|
-
'lease_access_conditions': access_conditions,
|
2315
|
-
'timeout': kwargs.pop('timeout', None)}
|
2316
|
-
options.update(kwargs)
|
2317
|
-
return options
|
2318
|
-
|
2319
1757
|
@distributed_trace
|
2320
|
-
def abort_copy(
|
2321
|
-
|
1758
|
+
def abort_copy(
|
1759
|
+
self, copy_id: Union[str, Dict[str, Any], BlobProperties],
|
1760
|
+
**kwargs: Any
|
1761
|
+
) -> None:
|
2322
1762
|
"""Abort an ongoing copy operation.
|
2323
1763
|
|
2324
1764
|
This will leave a destination blob with zero length and full metadata.
|
@@ -2339,15 +1779,14 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2339
1779
|
:dedent: 12
|
2340
1780
|
:caption: Abort copying a blob from URL.
|
2341
1781
|
"""
|
2342
|
-
options =
|
1782
|
+
options = _abort_copy_options(copy_id, **kwargs)
|
2343
1783
|
try:
|
2344
1784
|
self._client.blob.abort_copy_from_url(**options)
|
2345
1785
|
except HttpResponseError as error:
|
2346
1786
|
process_storage_error(error)
|
2347
1787
|
|
2348
1788
|
@distributed_trace
|
2349
|
-
def acquire_lease(self, lease_duration=-1, lease_id=None, **kwargs):
|
2350
|
-
# type: (int, Optional[str], **Any) -> BlobLeaseClient
|
1789
|
+
def acquire_lease(self, lease_duration: int =-1, lease_id: Optional[str] = None, **kwargs: Any) -> BlobLeaseClient:
|
2351
1790
|
"""Requests a new lease.
|
2352
1791
|
|
2353
1792
|
If the blob does not have an active lease, the Blob
|
@@ -2390,7 +1829,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2390
1829
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
2391
1830
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
2392
1831
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
2393
|
-
#other-client--per-operation-configuration>`
|
1832
|
+
#other-client--per-operation-configuration>`__.
|
2394
1833
|
:returns: A BlobLeaseClient object.
|
2395
1834
|
:rtype: ~azure.storage.blob.BlobLeaseClient
|
2396
1835
|
|
@@ -2403,13 +1842,12 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2403
1842
|
:dedent: 8
|
2404
1843
|
:caption: Acquiring a lease on a blob.
|
2405
1844
|
"""
|
2406
|
-
lease = BlobLeaseClient(self, lease_id=lease_id)
|
1845
|
+
lease = BlobLeaseClient(self, lease_id=lease_id)
|
2407
1846
|
lease.acquire(lease_duration=lease_duration, **kwargs)
|
2408
1847
|
return lease
|
2409
1848
|
|
2410
1849
|
@distributed_trace
|
2411
|
-
def set_standard_blob_tier(self, standard_blob_tier, **kwargs):
|
2412
|
-
# type: (Union[str, StandardBlobTier], Any) -> None
|
1850
|
+
def set_standard_blob_tier(self, standard_blob_tier: Union[str, "StandardBlobTier"], **kwargs: Any) -> None:
|
2413
1851
|
"""This operation sets the tier on a block blob.
|
2414
1852
|
|
2415
1853
|
A block blob's tier determines Hot/Cool/Archive storage type.
|
@@ -2430,18 +1868,20 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2430
1868
|
value that, when present, specifies the version of the blob to download.
|
2431
1869
|
|
2432
1870
|
.. versionadded:: 12.4.0
|
1871
|
+
|
2433
1872
|
This keyword argument was introduced in API version '2019-12-12'.
|
2434
1873
|
:keyword str if_tags_match_condition:
|
2435
1874
|
Specify a SQL where clause on blob tags to operate only on blob with a matching value.
|
2436
1875
|
eg. ``\"\\\"tagname\\\"='my tag'\"``
|
2437
1876
|
|
2438
1877
|
.. versionadded:: 12.4.0
|
1878
|
+
|
2439
1879
|
:keyword int timeout:
|
2440
1880
|
Sets the server-side timeout for the operation in seconds. For more details see
|
2441
1881
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
2442
1882
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
2443
1883
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
2444
|
-
#other-client--per-operation-configuration>`
|
1884
|
+
#other-client--per-operation-configuration>`__.
|
2445
1885
|
:keyword lease:
|
2446
1886
|
Required if the blob has an active lease. Value can be a BlobLeaseClient object
|
2447
1887
|
or the lease ID as a string.
|
@@ -2467,66 +1907,20 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2467
1907
|
except HttpResponseError as error:
|
2468
1908
|
process_storage_error(error)
|
2469
1909
|
|
2470
|
-
def _stage_block_options(
|
2471
|
-
self, block_id, # type: str
|
2472
|
-
data, # type: Union[Iterable[AnyStr], IO[AnyStr]]
|
2473
|
-
length=None, # type: Optional[int]
|
2474
|
-
**kwargs
|
2475
|
-
):
|
2476
|
-
# type: (...) -> Dict[str, Any]
|
2477
|
-
if self.require_encryption or (self.key_encryption_key is not None):
|
2478
|
-
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
2479
|
-
block_id = encode_base64(str(block_id))
|
2480
|
-
if isinstance(data, str):
|
2481
|
-
data = data.encode(kwargs.pop('encoding', 'UTF-8')) # type: ignore
|
2482
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
2483
|
-
if length is None:
|
2484
|
-
length = get_length(data)
|
2485
|
-
if length is None:
|
2486
|
-
length, data = read_length(data)
|
2487
|
-
if isinstance(data, bytes):
|
2488
|
-
data = data[:length]
|
2489
|
-
|
2490
|
-
validate_content = kwargs.pop('validate_content', False)
|
2491
|
-
cpk_scope_info = get_cpk_scope_info(kwargs)
|
2492
|
-
cpk = kwargs.pop('cpk', None)
|
2493
|
-
cpk_info = None
|
2494
|
-
if cpk:
|
2495
|
-
if self.scheme.lower() != 'https':
|
2496
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
2497
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
2498
|
-
encryption_algorithm=cpk.algorithm)
|
2499
|
-
|
2500
|
-
options = {
|
2501
|
-
'block_id': block_id,
|
2502
|
-
'content_length': length,
|
2503
|
-
'body': data,
|
2504
|
-
'transactional_content_md5': None,
|
2505
|
-
'timeout': kwargs.pop('timeout', None),
|
2506
|
-
'lease_access_conditions': access_conditions,
|
2507
|
-
'validate_content': validate_content,
|
2508
|
-
'cpk_scope_info': cpk_scope_info,
|
2509
|
-
'cpk_info': cpk_info,
|
2510
|
-
'cls': return_response_headers,
|
2511
|
-
}
|
2512
|
-
options.update(kwargs)
|
2513
|
-
return options
|
2514
|
-
|
2515
1910
|
@distributed_trace
|
2516
1911
|
def stage_block(
|
2517
|
-
|
2518
|
-
|
2519
|
-
|
2520
|
-
|
2521
|
-
|
2522
|
-
# type: (...) -> Dict[str, Any]
|
1912
|
+
self, block_id: str,
|
1913
|
+
data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]],
|
1914
|
+
length: Optional[int] = None,
|
1915
|
+
**kwargs: Any
|
1916
|
+
) -> Dict[str, Any]:
|
2523
1917
|
"""Creates a new block to be committed as part of a blob.
|
2524
1918
|
|
2525
1919
|
:param str block_id: A string value that identifies the block.
|
2526
1920
|
The string should be less than or equal to 64 bytes in size.
|
2527
1921
|
For a given blob, the block_id must be the same size for each block.
|
2528
1922
|
:param data: The blob data.
|
2529
|
-
:type data: Union[Iterable[AnyStr], IO[AnyStr]]
|
1923
|
+
:type data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]]
|
2530
1924
|
:param int length: Size of the block.
|
2531
1925
|
:keyword bool validate_content:
|
2532
1926
|
If true, calculates an MD5 hash for each chunk of the blob. The storage
|
@@ -2561,74 +1955,33 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2561
1955
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
2562
1956
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
2563
1957
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
2564
|
-
#other-client--per-operation-configuration>`
|
1958
|
+
#other-client--per-operation-configuration>`__.
|
2565
1959
|
:returns: Blob property dict.
|
2566
1960
|
:rtype: dict[str, Any]
|
2567
1961
|
"""
|
2568
|
-
|
2569
|
-
|
2570
|
-
|
1962
|
+
if self.require_encryption or (self.key_encryption_key is not None):
|
1963
|
+
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
1964
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
1965
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
1966
|
+
options = _stage_block_options(
|
1967
|
+
block_id=block_id,
|
1968
|
+
data=data,
|
2571
1969
|
length=length,
|
2572
1970
|
**kwargs)
|
2573
1971
|
try:
|
2574
|
-
return self._client.block_blob.stage_block(**options)
|
1972
|
+
return cast(Dict[str, Any], self._client.block_blob.stage_block(**options))
|
2575
1973
|
except HttpResponseError as error:
|
2576
1974
|
process_storage_error(error)
|
2577
1975
|
|
2578
|
-
def _stage_block_from_url_options(
|
2579
|
-
self, block_id, # type: str
|
2580
|
-
source_url, # type: str
|
2581
|
-
source_offset=None, # type: Optional[int]
|
2582
|
-
source_length=None, # type: Optional[int]
|
2583
|
-
source_content_md5=None, # type: Optional[Union[bytes, bytearray]]
|
2584
|
-
**kwargs
|
2585
|
-
):
|
2586
|
-
# type: (...) -> Dict[str, Any]
|
2587
|
-
source_authorization = kwargs.pop('source_authorization', None)
|
2588
|
-
if source_length is not None and source_offset is None:
|
2589
|
-
raise ValueError("Source offset value must not be None if length is set.")
|
2590
|
-
if source_length is not None:
|
2591
|
-
source_length = source_offset + source_length - 1
|
2592
|
-
block_id = encode_base64(str(block_id))
|
2593
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
2594
|
-
range_header = None
|
2595
|
-
if source_offset is not None:
|
2596
|
-
range_header, _ = validate_and_format_range_headers(source_offset, source_length)
|
2597
|
-
|
2598
|
-
cpk_scope_info = get_cpk_scope_info(kwargs)
|
2599
|
-
cpk = kwargs.pop('cpk', None)
|
2600
|
-
cpk_info = None
|
2601
|
-
if cpk:
|
2602
|
-
if self.scheme.lower() != 'https':
|
2603
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
2604
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
2605
|
-
encryption_algorithm=cpk.algorithm)
|
2606
|
-
options = {
|
2607
|
-
'copy_source_authorization': source_authorization,
|
2608
|
-
'block_id': block_id,
|
2609
|
-
'content_length': 0,
|
2610
|
-
'source_url': source_url,
|
2611
|
-
'source_range': range_header,
|
2612
|
-
'source_content_md5': bytearray(source_content_md5) if source_content_md5 else None,
|
2613
|
-
'timeout': kwargs.pop('timeout', None),
|
2614
|
-
'lease_access_conditions': access_conditions,
|
2615
|
-
'cpk_scope_info': cpk_scope_info,
|
2616
|
-
'cpk_info': cpk_info,
|
2617
|
-
'cls': return_response_headers,
|
2618
|
-
}
|
2619
|
-
options.update(kwargs)
|
2620
|
-
return options
|
2621
|
-
|
2622
1976
|
@distributed_trace
|
2623
1977
|
def stage_block_from_url(
|
2624
|
-
|
2625
|
-
|
2626
|
-
|
2627
|
-
|
2628
|
-
|
2629
|
-
|
2630
|
-
|
2631
|
-
# type: (...) -> Dict[str, Any]
|
1978
|
+
self, block_id: str,
|
1979
|
+
source_url: str,
|
1980
|
+
source_offset: Optional[int] = None,
|
1981
|
+
source_length: Optional[int] = None,
|
1982
|
+
source_content_md5: Optional[Union[bytes, bytearray]] = None,
|
1983
|
+
**kwargs: Any
|
1984
|
+
) -> Dict[str, Any]:
|
2632
1985
|
"""Creates a new block to be committed as part of a blob where
|
2633
1986
|
the contents are read from a URL.
|
2634
1987
|
|
@@ -2665,38 +2018,32 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2665
2018
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
2666
2019
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
2667
2020
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
2668
|
-
#other-client--per-operation-configuration>`
|
2021
|
+
#other-client--per-operation-configuration>`__.
|
2669
2022
|
:keyword str source_authorization:
|
2670
2023
|
Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is
|
2671
2024
|
the prefix of the source_authorization string.
|
2672
2025
|
:returns: Blob property dict.
|
2673
2026
|
:rtype: dict[str, Any]
|
2674
2027
|
"""
|
2675
|
-
|
2676
|
-
|
2677
|
-
|
2028
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
2029
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
2030
|
+
options = _stage_block_from_url_options(
|
2031
|
+
block_id=block_id,
|
2032
|
+
source_url=source_url,
|
2678
2033
|
source_offset=source_offset,
|
2679
2034
|
source_length=source_length,
|
2680
2035
|
source_content_md5=source_content_md5,
|
2681
2036
|
**kwargs)
|
2682
2037
|
try:
|
2683
|
-
return self._client.block_blob.stage_block_from_url(**options)
|
2038
|
+
return cast(Dict[str, Any], self._client.block_blob.stage_block_from_url(**options))
|
2684
2039
|
except HttpResponseError as error:
|
2685
2040
|
process_storage_error(error)
|
2686
2041
|
|
2687
|
-
def _get_block_list_result(self, blocks):
|
2688
|
-
# type: (BlockList) -> Tuple[List[BlobBlock], List[BlobBlock]]
|
2689
|
-
committed = [] # type: List
|
2690
|
-
uncommitted = [] # type: List
|
2691
|
-
if blocks.committed_blocks:
|
2692
|
-
committed = [BlobBlock._from_generated(b) for b in blocks.committed_blocks] # pylint: disable=protected-access
|
2693
|
-
if blocks.uncommitted_blocks:
|
2694
|
-
uncommitted = [BlobBlock._from_generated(b) for b in blocks.uncommitted_blocks] # pylint: disable=protected-access
|
2695
|
-
return committed, uncommitted
|
2696
|
-
|
2697
2042
|
@distributed_trace
|
2698
|
-
def get_block_list(
|
2699
|
-
|
2043
|
+
def get_block_list(
|
2044
|
+
self, block_list_type: str = "committed",
|
2045
|
+
**kwargs: Any
|
2046
|
+
) -> Tuple[List[BlobBlock], List[BlobBlock]]:
|
2700
2047
|
"""The Get Block List operation retrieves the list of blocks that have
|
2701
2048
|
been uploaded as part of a block blob.
|
2702
2049
|
|
@@ -2718,9 +2065,9 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2718
2065
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
2719
2066
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
2720
2067
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
2721
|
-
#other-client--per-operation-configuration>`
|
2068
|
+
#other-client--per-operation-configuration>`__.
|
2722
2069
|
:returns: A tuple of two lists - committed and uncommitted blocks
|
2723
|
-
:rtype:
|
2070
|
+
:rtype: Tuple[List[BlobBlock], List[BlobBlock]]
|
2724
2071
|
"""
|
2725
2072
|
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
2726
2073
|
mod_conditions = get_modify_conditions(kwargs)
|
@@ -2734,86 +2081,15 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2734
2081
|
**kwargs)
|
2735
2082
|
except HttpResponseError as error:
|
2736
2083
|
process_storage_error(error)
|
2737
|
-
return
|
2738
|
-
|
2739
|
-
def _commit_block_list_options( # type: ignore
|
2740
|
-
self, block_list, # type: List[BlobBlock]
|
2741
|
-
content_settings=None, # type: Optional[ContentSettings]
|
2742
|
-
metadata=None, # type: Optional[Dict[str, str]]
|
2743
|
-
**kwargs
|
2744
|
-
):
|
2745
|
-
# type: (...) -> Dict[str, Any]
|
2746
|
-
if self.require_encryption or (self.key_encryption_key is not None):
|
2747
|
-
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
2748
|
-
block_lookup = BlockLookupList(committed=[], uncommitted=[], latest=[])
|
2749
|
-
for block in block_list:
|
2750
|
-
try:
|
2751
|
-
if block.state.value == 'committed':
|
2752
|
-
block_lookup.committed.append(encode_base64(str(block.id)))
|
2753
|
-
elif block.state.value == 'uncommitted':
|
2754
|
-
block_lookup.uncommitted.append(encode_base64(str(block.id)))
|
2755
|
-
else:
|
2756
|
-
block_lookup.latest.append(encode_base64(str(block.id)))
|
2757
|
-
except AttributeError:
|
2758
|
-
block_lookup.latest.append(encode_base64(str(block)))
|
2759
|
-
headers = kwargs.pop('headers', {})
|
2760
|
-
headers.update(add_metadata_headers(metadata))
|
2761
|
-
blob_headers = None
|
2762
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
2763
|
-
mod_conditions = get_modify_conditions(kwargs)
|
2764
|
-
if content_settings:
|
2765
|
-
blob_headers = BlobHTTPHeaders(
|
2766
|
-
blob_cache_control=content_settings.cache_control,
|
2767
|
-
blob_content_type=content_settings.content_type,
|
2768
|
-
blob_content_md5=content_settings.content_md5,
|
2769
|
-
blob_content_encoding=content_settings.content_encoding,
|
2770
|
-
blob_content_language=content_settings.content_language,
|
2771
|
-
blob_content_disposition=content_settings.content_disposition
|
2772
|
-
)
|
2773
|
-
|
2774
|
-
validate_content = kwargs.pop('validate_content', False)
|
2775
|
-
cpk_scope_info = get_cpk_scope_info(kwargs)
|
2776
|
-
cpk = kwargs.pop('cpk', None)
|
2777
|
-
cpk_info = None
|
2778
|
-
if cpk:
|
2779
|
-
if self.scheme.lower() != 'https':
|
2780
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
2781
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
2782
|
-
encryption_algorithm=cpk.algorithm)
|
2783
|
-
|
2784
|
-
immutability_policy = kwargs.pop('immutability_policy', None)
|
2785
|
-
if immutability_policy:
|
2786
|
-
kwargs['immutability_policy_expiry'] = immutability_policy.expiry_time
|
2787
|
-
kwargs['immutability_policy_mode'] = immutability_policy.policy_mode
|
2788
|
-
|
2789
|
-
tier = kwargs.pop('standard_blob_tier', None)
|
2790
|
-
blob_tags_string = serialize_blob_tags_header(kwargs.pop('tags', None))
|
2791
|
-
|
2792
|
-
options = {
|
2793
|
-
'blocks': block_lookup,
|
2794
|
-
'blob_http_headers': blob_headers,
|
2795
|
-
'lease_access_conditions': access_conditions,
|
2796
|
-
'timeout': kwargs.pop('timeout', None),
|
2797
|
-
'modified_access_conditions': mod_conditions,
|
2798
|
-
'cls': return_response_headers,
|
2799
|
-
'validate_content': validate_content,
|
2800
|
-
'cpk_scope_info': cpk_scope_info,
|
2801
|
-
'cpk_info': cpk_info,
|
2802
|
-
'tier': tier.value if tier else None,
|
2803
|
-
'blob_tags_string': blob_tags_string,
|
2804
|
-
'headers': headers
|
2805
|
-
}
|
2806
|
-
options.update(kwargs)
|
2807
|
-
return options
|
2084
|
+
return _get_block_list_result(blocks)
|
2808
2085
|
|
2809
2086
|
@distributed_trace
|
2810
|
-
def commit_block_list(
|
2811
|
-
|
2812
|
-
|
2813
|
-
|
2814
|
-
|
2815
|
-
|
2816
|
-
# type: (...) -> Dict[str, Union[str, datetime]]
|
2087
|
+
def commit_block_list(
|
2088
|
+
self, block_list: List[BlobBlock],
|
2089
|
+
content_settings: Optional["ContentSettings"] = None,
|
2090
|
+
metadata: Optional[Dict[str, str]] = None,
|
2091
|
+
**kwargs: Any
|
2092
|
+
) -> Dict[str, Union[str, datetime]]:
|
2817
2093
|
"""The Commit Block List operation writes a blob by specifying the list of
|
2818
2094
|
block IDs that make up the blob.
|
2819
2095
|
|
@@ -2830,7 +2106,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2830
2106
|
The tag set may contain at most 10 tags. Tag keys must be between 1 and 128 characters,
|
2831
2107
|
and tag values must be between 0 and 256 characters.
|
2832
2108
|
Valid tag key and value characters include: lowercase and uppercase letters, digits (0-9),
|
2833
|
-
space (
|
2109
|
+
space (' '), plus (+), minus (-), period (.), solidus (/), colon (:), equals (=), underscore (_)
|
2834
2110
|
|
2835
2111
|
.. versionadded:: 12.4.0
|
2836
2112
|
|
@@ -2901,23 +2177,26 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2901
2177
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
2902
2178
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
2903
2179
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
2904
|
-
#other-client--per-operation-configuration>`
|
2180
|
+
#other-client--per-operation-configuration>`__.
|
2905
2181
|
:returns: Blob-updated property dict (Etag and last modified).
|
2906
2182
|
:rtype: dict(str, Any)
|
2907
2183
|
"""
|
2908
|
-
|
2909
|
-
|
2184
|
+
if self.require_encryption or (self.key_encryption_key is not None):
|
2185
|
+
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
2186
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
2187
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
2188
|
+
options = _commit_block_list_options(
|
2189
|
+
block_list=block_list,
|
2910
2190
|
content_settings=content_settings,
|
2911
2191
|
metadata=metadata,
|
2912
2192
|
**kwargs)
|
2913
2193
|
try:
|
2914
|
-
return self._client.block_blob.commit_block_list(**options)
|
2194
|
+
return cast(Dict[str, Any], self._client.block_blob.commit_block_list(**options))
|
2915
2195
|
except HttpResponseError as error:
|
2916
2196
|
process_storage_error(error)
|
2917
2197
|
|
2918
2198
|
@distributed_trace
|
2919
|
-
def set_premium_page_blob_tier(self, premium_page_blob_tier, **kwargs):
|
2920
|
-
# type: (Union[str, PremiumPageBlobTier], **Any) -> None
|
2199
|
+
def set_premium_page_blob_tier(self, premium_page_blob_tier: "PremiumPageBlobTier", **kwargs: Any) -> None:
|
2921
2200
|
"""Sets the page blob tiers on the blob. This API is only supported for page blobs on premium accounts.
|
2922
2201
|
|
2923
2202
|
:param premium_page_blob_tier:
|
@@ -2936,7 +2215,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2936
2215
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
2937
2216
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
2938
2217
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
2939
|
-
#other-client--per-operation-configuration>`
|
2218
|
+
#other-client--per-operation-configuration>`__.
|
2940
2219
|
:keyword lease:
|
2941
2220
|
Required if the blob has an active lease. Value can be a BlobLeaseClient object
|
2942
2221
|
or the lease ID as a string.
|
@@ -2957,25 +2236,8 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2957
2236
|
except HttpResponseError as error:
|
2958
2237
|
process_storage_error(error)
|
2959
2238
|
|
2960
|
-
def _set_blob_tags_options(self, tags=None, **kwargs):
|
2961
|
-
# type: (Optional[Dict[str, str]], **Any) -> Dict[str, Any]
|
2962
|
-
tags = serialize_blob_tags(tags)
|
2963
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
2964
|
-
mod_conditions = get_modify_conditions(kwargs)
|
2965
|
-
version_id = get_version_id(self.version_id, kwargs)
|
2966
|
-
|
2967
|
-
options = {
|
2968
|
-
'tags': tags,
|
2969
|
-
'lease_access_conditions': access_conditions,
|
2970
|
-
'modified_access_conditions': mod_conditions,
|
2971
|
-
'version_id': version_id,
|
2972
|
-
'cls': return_response_headers}
|
2973
|
-
options.update(kwargs)
|
2974
|
-
return options
|
2975
|
-
|
2976
2239
|
@distributed_trace
|
2977
|
-
def set_blob_tags(self, tags=None, **kwargs):
|
2978
|
-
# type: (Optional[Dict[str, str]], **Any) -> Dict[str, Any]
|
2240
|
+
def set_blob_tags(self, tags: Optional[Dict[str, str]] = None, **kwargs: Any) -> Dict[str, Any]:
|
2979
2241
|
"""The Set Tags operation enables users to set tags on a blob or specific blob version, but not snapshot.
|
2980
2242
|
Each call to this operation replaces all existing tags attached to the blob. To remove all
|
2981
2243
|
tags from the blob, call this operation with no tags set.
|
@@ -2988,7 +2250,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
2988
2250
|
The tag set may contain at most 10 tags. Tag keys must be between 1 and 128 characters,
|
2989
2251
|
and tag values must be between 0 and 256 characters.
|
2990
2252
|
Valid tag key and value characters include: lowercase and uppercase letters, digits (0-9),
|
2991
|
-
space (
|
2253
|
+
space (' '), plus (+), minus (-), period (.), solidus (/), colon (:), equals (=), underscore (_)
|
2992
2254
|
:type tags: dict(str, str)
|
2993
2255
|
:keyword str version_id:
|
2994
2256
|
The version id parameter is an opaque DateTime
|
@@ -3012,40 +2274,25 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3012
2274
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
3013
2275
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
3014
2276
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
3015
|
-
#other-client--per-operation-configuration>`
|
2277
|
+
#other-client--per-operation-configuration>`__.
|
3016
2278
|
:returns: Blob-updated property dict (Etag and last modified)
|
3017
2279
|
:rtype: Dict[str, Any]
|
3018
2280
|
"""
|
3019
|
-
|
2281
|
+
version_id = get_version_id(self.version_id, kwargs)
|
2282
|
+
options = _set_blob_tags_options(version_id=version_id, tags=tags, **kwargs)
|
3020
2283
|
try:
|
3021
|
-
return self._client.blob.set_tags(**options)
|
2284
|
+
return cast(Dict[str, Any], self._client.blob.set_tags(**options))
|
3022
2285
|
except HttpResponseError as error:
|
3023
2286
|
process_storage_error(error)
|
3024
2287
|
|
3025
|
-
def _get_blob_tags_options(self, **kwargs):
|
3026
|
-
# type: (**Any) -> Dict[str, str]
|
3027
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
3028
|
-
mod_conditions = get_modify_conditions(kwargs)
|
3029
|
-
version_id = get_version_id(self.version_id, kwargs)
|
3030
|
-
|
3031
|
-
options = {
|
3032
|
-
'version_id': version_id,
|
3033
|
-
'snapshot': self.snapshot,
|
3034
|
-
'lease_access_conditions': access_conditions,
|
3035
|
-
'modified_access_conditions': mod_conditions,
|
3036
|
-
'timeout': kwargs.pop('timeout', None),
|
3037
|
-
'cls': return_headers_and_deserialized}
|
3038
|
-
return options
|
3039
|
-
|
3040
2288
|
@distributed_trace
|
3041
|
-
def get_blob_tags(self, **kwargs):
|
3042
|
-
# type: (**Any) -> Dict[str, str]
|
2289
|
+
def get_blob_tags(self, **kwargs: Any) -> Dict[str, str]:
|
3043
2290
|
"""The Get Tags operation enables users to get tags on a blob or specific blob version, or snapshot.
|
3044
2291
|
|
3045
2292
|
.. versionadded:: 12.4.0
|
3046
2293
|
This operation was introduced in API version '2019-12-12'.
|
3047
2294
|
|
3048
|
-
:keyword str version_id:
|
2295
|
+
:keyword Optional[str] version_id:
|
3049
2296
|
The version id parameter is an opaque DateTime
|
3050
2297
|
value that, when present, specifies the version of the blob to add tags to.
|
3051
2298
|
:keyword str if_tags_match_condition:
|
@@ -3060,58 +2307,25 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3060
2307
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
3061
2308
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
3062
2309
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
3063
|
-
#other-client--per-operation-configuration>`
|
2310
|
+
#other-client--per-operation-configuration>`__.
|
3064
2311
|
:returns: Key value pairs of blob tags.
|
3065
2312
|
:rtype: Dict[str, str]
|
3066
2313
|
"""
|
3067
|
-
|
2314
|
+
version_id = get_version_id(self.version_id, kwargs)
|
2315
|
+
options = _get_blob_tags_options(version_id=version_id, snapshot=self.snapshot, **kwargs)
|
3068
2316
|
try:
|
3069
2317
|
_, tags = self._client.blob.get_tags(**options)
|
3070
|
-
return parse_tags(tags)
|
2318
|
+
return cast(Dict[str, str], parse_tags(tags))
|
3071
2319
|
except HttpResponseError as error:
|
3072
2320
|
process_storage_error(error)
|
3073
2321
|
|
3074
|
-
def _get_page_ranges_options( # type: ignore
|
3075
|
-
self, offset=None, # type: Optional[int]
|
3076
|
-
length=None, # type: Optional[int]
|
3077
|
-
previous_snapshot_diff=None, # type: Optional[Union[str, Dict[str, Any]]]
|
3078
|
-
**kwargs
|
3079
|
-
):
|
3080
|
-
# type: (...) -> Dict[str, Any]
|
3081
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
3082
|
-
mod_conditions = get_modify_conditions(kwargs)
|
3083
|
-
if length is not None and offset is None:
|
3084
|
-
raise ValueError("Offset value must not be None if length is set.")
|
3085
|
-
if length is not None:
|
3086
|
-
length = offset + length - 1 # Reformat to an inclusive range index
|
3087
|
-
page_range, _ = validate_and_format_range_headers(
|
3088
|
-
offset, length, start_range_required=False, end_range_required=False, align_to_page=True
|
3089
|
-
)
|
3090
|
-
options = {
|
3091
|
-
'snapshot': self.snapshot,
|
3092
|
-
'lease_access_conditions': access_conditions,
|
3093
|
-
'modified_access_conditions': mod_conditions,
|
3094
|
-
'timeout': kwargs.pop('timeout', None),
|
3095
|
-
'range': page_range}
|
3096
|
-
if previous_snapshot_diff:
|
3097
|
-
try:
|
3098
|
-
options['prevsnapshot'] = previous_snapshot_diff.snapshot # type: ignore
|
3099
|
-
except AttributeError:
|
3100
|
-
try:
|
3101
|
-
options['prevsnapshot'] = previous_snapshot_diff['snapshot'] # type: ignore
|
3102
|
-
except TypeError:
|
3103
|
-
options['prevsnapshot'] = previous_snapshot_diff
|
3104
|
-
options.update(kwargs)
|
3105
|
-
return options
|
3106
|
-
|
3107
2322
|
@distributed_trace
|
3108
|
-
def get_page_ranges(
|
3109
|
-
|
3110
|
-
|
3111
|
-
|
3112
|
-
|
3113
|
-
|
3114
|
-
# type: (...) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]
|
2323
|
+
def get_page_ranges(
|
2324
|
+
self, offset: Optional[int] = None,
|
2325
|
+
length: Optional[int] = None,
|
2326
|
+
previous_snapshot_diff: Optional[Union[str, Dict[str, Any]]] = None,
|
2327
|
+
**kwargs: Any
|
2328
|
+
) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]:
|
3115
2329
|
"""DEPRECATED: Returns the list of valid page ranges for a Page Blob or snapshot
|
3116
2330
|
of a page blob.
|
3117
2331
|
|
@@ -3165,7 +2379,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3165
2379
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
3166
2380
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
3167
2381
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
3168
|
-
#other-client--per-operation-configuration>`
|
2382
|
+
#other-client--per-operation-configuration>`__.
|
3169
2383
|
:returns:
|
3170
2384
|
A tuple of two lists of page ranges as dictionaries with 'start' and 'end' keys.
|
3171
2385
|
The first element are filled page ranges, the 2nd element is cleared page ranges.
|
@@ -3176,7 +2390,8 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3176
2390
|
DeprecationWarning
|
3177
2391
|
)
|
3178
2392
|
|
3179
|
-
options =
|
2393
|
+
options = _get_page_ranges_options(
|
2394
|
+
snapshot=self.snapshot,
|
3180
2395
|
offset=offset,
|
3181
2396
|
length=length,
|
3182
2397
|
previous_snapshot_diff=previous_snapshot_diff,
|
@@ -3192,13 +2407,13 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3192
2407
|
|
3193
2408
|
@distributed_trace
|
3194
2409
|
def list_page_ranges(
|
3195
|
-
|
3196
|
-
|
3197
|
-
|
3198
|
-
|
3199
|
-
|
3200
|
-
|
3201
|
-
|
2410
|
+
self,
|
2411
|
+
*,
|
2412
|
+
offset: Optional[int] = None,
|
2413
|
+
length: Optional[int] = None,
|
2414
|
+
previous_snapshot: Optional[Union[str, Dict[str, Any]]] = None,
|
2415
|
+
**kwargs: Any
|
2416
|
+
) -> ItemPaged[PageRange]:
|
3202
2417
|
"""Returns the list of valid page ranges for a Page Blob or snapshot
|
3203
2418
|
of a page blob. If `previous_snapshot` is specified, the result will be
|
3204
2419
|
a diff of changes between the target blob and the previous snapshot.
|
@@ -3257,12 +2472,13 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3257
2472
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
3258
2473
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
3259
2474
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
3260
|
-
#other-client--per-operation-configuration>`
|
2475
|
+
#other-client--per-operation-configuration>`__.
|
3261
2476
|
:returns: An iterable (auto-paging) of PageRange.
|
3262
2477
|
:rtype: ~azure.core.paging.ItemPaged[~azure.storage.blob.PageRange]
|
3263
2478
|
"""
|
3264
2479
|
results_per_page = kwargs.pop('results_per_page', None)
|
3265
|
-
options =
|
2480
|
+
options = _get_page_ranges_options(
|
2481
|
+
snapshot=self.snapshot,
|
3266
2482
|
offset=offset,
|
3267
2483
|
length=length,
|
3268
2484
|
previous_snapshot_diff=previous_snapshot,
|
@@ -3282,12 +2498,11 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3282
2498
|
|
3283
2499
|
@distributed_trace
|
3284
2500
|
def get_page_range_diff_for_managed_disk(
|
3285
|
-
|
3286
|
-
|
3287
|
-
|
3288
|
-
|
3289
|
-
|
3290
|
-
# type: (...) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]
|
2501
|
+
self, previous_snapshot_url: str,
|
2502
|
+
offset: Optional[int] = None,
|
2503
|
+
length:Optional[int] = None,
|
2504
|
+
**kwargs: Any
|
2505
|
+
) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]:
|
3291
2506
|
"""Returns the list of valid page ranges for a managed disk or snapshot.
|
3292
2507
|
|
3293
2508
|
.. note::
|
@@ -3340,13 +2555,14 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3340
2555
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
3341
2556
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
3342
2557
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
3343
|
-
#other-client--per-operation-configuration>`
|
2558
|
+
#other-client--per-operation-configuration>`__.
|
3344
2559
|
:returns:
|
3345
2560
|
A tuple of two lists of page ranges as dictionaries with 'start' and 'end' keys.
|
3346
2561
|
The first element are filled page ranges, the 2nd element is cleared page ranges.
|
3347
2562
|
:rtype: tuple(list(dict(str, str), list(dict(str, str))
|
3348
2563
|
"""
|
3349
|
-
options =
|
2564
|
+
options = _get_page_ranges_options(
|
2565
|
+
snapshot=self.snapshot,
|
3350
2566
|
offset=offset,
|
3351
2567
|
length=length,
|
3352
2568
|
prev_snapshot_url=previous_snapshot_url,
|
@@ -3357,25 +2573,12 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3357
2573
|
process_storage_error(error)
|
3358
2574
|
return get_page_ranges_result(ranges)
|
3359
2575
|
|
3360
|
-
def _set_sequence_number_options(self, sequence_number_action, sequence_number=None, **kwargs):
|
3361
|
-
# type: (Union[str, SequenceNumberAction], Optional[str], **Any) -> Dict[str, Any]
|
3362
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
3363
|
-
mod_conditions = get_modify_conditions(kwargs)
|
3364
|
-
if sequence_number_action is None:
|
3365
|
-
raise ValueError("A sequence number action must be specified")
|
3366
|
-
options = {
|
3367
|
-
'sequence_number_action': sequence_number_action,
|
3368
|
-
'timeout': kwargs.pop('timeout', None),
|
3369
|
-
'blob_sequence_number': sequence_number,
|
3370
|
-
'lease_access_conditions': access_conditions,
|
3371
|
-
'modified_access_conditions': mod_conditions,
|
3372
|
-
'cls': return_response_headers}
|
3373
|
-
options.update(kwargs)
|
3374
|
-
return options
|
3375
|
-
|
3376
2576
|
@distributed_trace
|
3377
|
-
def set_sequence_number(
|
3378
|
-
|
2577
|
+
def set_sequence_number(
|
2578
|
+
self, sequence_number_action: Union[str, "SequenceNumberAction"],
|
2579
|
+
sequence_number: Optional[str] = None,
|
2580
|
+
**kwargs: Any
|
2581
|
+
) -> Dict[str, Union[str, datetime]]:
|
3379
2582
|
"""Sets the blob sequence number.
|
3380
2583
|
|
3381
2584
|
:param str sequence_number_action:
|
@@ -3417,44 +2620,18 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3417
2620
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
3418
2621
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
3419
2622
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
3420
|
-
#other-client--per-operation-configuration>`
|
2623
|
+
#other-client--per-operation-configuration>`__.
|
3421
2624
|
:returns: Blob-updated property dict (Etag and last modified).
|
3422
2625
|
:rtype: dict(str, Any)
|
3423
2626
|
"""
|
3424
|
-
options =
|
3425
|
-
sequence_number_action, sequence_number=sequence_number, **kwargs)
|
2627
|
+
options = _set_sequence_number_options(sequence_number_action, sequence_number=sequence_number, **kwargs)
|
3426
2628
|
try:
|
3427
|
-
return self._client.page_blob.update_sequence_number(**options)
|
2629
|
+
return cast(Dict[str, Any], self._client.page_blob.update_sequence_number(**options))
|
3428
2630
|
except HttpResponseError as error:
|
3429
2631
|
process_storage_error(error)
|
3430
2632
|
|
3431
|
-
def _resize_blob_options(self, size, **kwargs):
|
3432
|
-
# type: (int, **Any) -> Dict[str, Any]
|
3433
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
3434
|
-
mod_conditions = get_modify_conditions(kwargs)
|
3435
|
-
if size is None:
|
3436
|
-
raise ValueError("A content length must be specified for a Page Blob.")
|
3437
|
-
|
3438
|
-
cpk = kwargs.pop('cpk', None)
|
3439
|
-
cpk_info = None
|
3440
|
-
if cpk:
|
3441
|
-
if self.scheme.lower() != 'https':
|
3442
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
3443
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
3444
|
-
encryption_algorithm=cpk.algorithm)
|
3445
|
-
options = {
|
3446
|
-
'blob_content_length': size,
|
3447
|
-
'timeout': kwargs.pop('timeout', None),
|
3448
|
-
'lease_access_conditions': access_conditions,
|
3449
|
-
'modified_access_conditions': mod_conditions,
|
3450
|
-
'cpk_info': cpk_info,
|
3451
|
-
'cls': return_response_headers}
|
3452
|
-
options.update(kwargs)
|
3453
|
-
return options
|
3454
|
-
|
3455
2633
|
@distributed_trace
|
3456
|
-
def resize_blob(self, size, **kwargs):
|
3457
|
-
# type: (int, **Any) -> Dict[str, Union[str, datetime]]
|
2634
|
+
def resize_blob(self, size: int, **kwargs: Any) -> Dict[str, Union[str, datetime]]:
|
3458
2635
|
"""Resizes a page blob to the specified size.
|
3459
2636
|
|
3460
2637
|
If the specified value is less than the current size of the blob,
|
@@ -3499,74 +2676,25 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3499
2676
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
3500
2677
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
3501
2678
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
3502
|
-
#other-client--per-operation-configuration>`
|
2679
|
+
#other-client--per-operation-configuration>`__.
|
3503
2680
|
:returns: Blob-updated property dict (Etag and last modified).
|
3504
2681
|
:rtype: dict(str, Any)
|
3505
2682
|
"""
|
3506
|
-
|
2683
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
2684
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
2685
|
+
options = _resize_blob_options(size=size, **kwargs)
|
3507
2686
|
try:
|
3508
|
-
return self._client.page_blob.resize(**options)
|
2687
|
+
return cast(Dict[str, Any], self._client.page_blob.resize(**options))
|
3509
2688
|
except HttpResponseError as error:
|
3510
2689
|
process_storage_error(error)
|
3511
2690
|
|
3512
|
-
def _upload_page_options( # type: ignore
|
3513
|
-
self, page, # type: bytes
|
3514
|
-
offset, # type: int
|
3515
|
-
length, # type: int
|
3516
|
-
**kwargs
|
3517
|
-
):
|
3518
|
-
# type: (...) -> Dict[str, Any]
|
3519
|
-
if isinstance(page, str):
|
3520
|
-
page = page.encode(kwargs.pop('encoding', 'UTF-8'))
|
3521
|
-
if self.require_encryption or (self.key_encryption_key is not None):
|
3522
|
-
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
3523
|
-
|
3524
|
-
if offset is None or offset % 512 != 0:
|
3525
|
-
raise ValueError("offset must be an integer that aligns with 512 page size")
|
3526
|
-
if length is None or length % 512 != 0:
|
3527
|
-
raise ValueError("length must be an integer that aligns with 512 page size")
|
3528
|
-
end_range = offset + length - 1 # Reformat to an inclusive range index
|
3529
|
-
content_range = f'bytes={offset}-{end_range}' # type: ignore
|
3530
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
3531
|
-
seq_conditions = SequenceNumberAccessConditions(
|
3532
|
-
if_sequence_number_less_than_or_equal_to=kwargs.pop('if_sequence_number_lte', None),
|
3533
|
-
if_sequence_number_less_than=kwargs.pop('if_sequence_number_lt', None),
|
3534
|
-
if_sequence_number_equal_to=kwargs.pop('if_sequence_number_eq', None)
|
3535
|
-
)
|
3536
|
-
mod_conditions = get_modify_conditions(kwargs)
|
3537
|
-
cpk_scope_info = get_cpk_scope_info(kwargs)
|
3538
|
-
validate_content = kwargs.pop('validate_content', False)
|
3539
|
-
cpk = kwargs.pop('cpk', None)
|
3540
|
-
cpk_info = None
|
3541
|
-
if cpk:
|
3542
|
-
if self.scheme.lower() != 'https':
|
3543
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
3544
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
3545
|
-
encryption_algorithm=cpk.algorithm)
|
3546
|
-
options = {
|
3547
|
-
'body': page[:length],
|
3548
|
-
'content_length': length,
|
3549
|
-
'transactional_content_md5': None,
|
3550
|
-
'timeout': kwargs.pop('timeout', None),
|
3551
|
-
'range': content_range,
|
3552
|
-
'lease_access_conditions': access_conditions,
|
3553
|
-
'sequence_number_access_conditions': seq_conditions,
|
3554
|
-
'modified_access_conditions': mod_conditions,
|
3555
|
-
'validate_content': validate_content,
|
3556
|
-
'cpk_scope_info': cpk_scope_info,
|
3557
|
-
'cpk_info': cpk_info,
|
3558
|
-
'cls': return_response_headers}
|
3559
|
-
options.update(kwargs)
|
3560
|
-
return options
|
3561
|
-
|
3562
2691
|
@distributed_trace
|
3563
|
-
def upload_page(
|
3564
|
-
|
3565
|
-
|
3566
|
-
|
3567
|
-
|
3568
|
-
|
3569
|
-
# type: (...) -> Dict[str, Union[str, datetime]]
|
2692
|
+
def upload_page(
|
2693
|
+
self, page: bytes,
|
2694
|
+
offset: int,
|
2695
|
+
length: int,
|
2696
|
+
**kwargs: Any
|
2697
|
+
) -> Dict[str, Union[str, datetime]]:
|
3570
2698
|
"""The Upload Pages operation writes a range of pages to a page blob.
|
3571
2699
|
|
3572
2700
|
:param bytes page:
|
@@ -3644,89 +2772,32 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3644
2772
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
3645
2773
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
3646
2774
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
3647
|
-
#other-client--per-operation-configuration>`
|
2775
|
+
#other-client--per-operation-configuration>`__.
|
3648
2776
|
:returns: Blob-updated property dict (Etag and last modified).
|
3649
2777
|
:rtype: dict(str, Any)
|
3650
2778
|
"""
|
3651
|
-
|
2779
|
+
if self.require_encryption or (self.key_encryption_key is not None):
|
2780
|
+
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
2781
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
2782
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
2783
|
+
options = _upload_page_options(
|
3652
2784
|
page=page,
|
3653
2785
|
offset=offset,
|
3654
2786
|
length=length,
|
3655
2787
|
**kwargs)
|
3656
2788
|
try:
|
3657
|
-
return self._client.page_blob.upload_pages(**options)
|
2789
|
+
return cast(Dict[str, Any], self._client.page_blob.upload_pages(**options))
|
3658
2790
|
except HttpResponseError as error:
|
3659
2791
|
process_storage_error(error)
|
3660
2792
|
|
3661
|
-
def _upload_pages_from_url_options( # type: ignore
|
3662
|
-
self, source_url, # type: str
|
3663
|
-
offset, # type: int
|
3664
|
-
length, # type: int
|
3665
|
-
source_offset, # type: int
|
3666
|
-
**kwargs
|
3667
|
-
):
|
3668
|
-
# type: (...) -> Dict[str, Any]
|
3669
|
-
if self.require_encryption or (self.key_encryption_key is not None):
|
3670
|
-
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
3671
|
-
|
3672
|
-
# TODO: extract the code to a method format_range
|
3673
|
-
if offset is None or offset % 512 != 0:
|
3674
|
-
raise ValueError("offset must be an integer that aligns with 512 page size")
|
3675
|
-
if length is None or length % 512 != 0:
|
3676
|
-
raise ValueError("length must be an integer that aligns with 512 page size")
|
3677
|
-
if source_offset is None or offset % 512 != 0:
|
3678
|
-
raise ValueError("source_offset must be an integer that aligns with 512 page size")
|
3679
|
-
|
3680
|
-
# Format range
|
3681
|
-
end_range = offset + length - 1
|
3682
|
-
destination_range = f'bytes={offset}-{end_range}'
|
3683
|
-
source_range = f'bytes={source_offset}-{source_offset + length - 1}' # should subtract 1 here?
|
3684
|
-
|
3685
|
-
seq_conditions = SequenceNumberAccessConditions(
|
3686
|
-
if_sequence_number_less_than_or_equal_to=kwargs.pop('if_sequence_number_lte', None),
|
3687
|
-
if_sequence_number_less_than=kwargs.pop('if_sequence_number_lt', None),
|
3688
|
-
if_sequence_number_equal_to=kwargs.pop('if_sequence_number_eq', None)
|
3689
|
-
)
|
3690
|
-
source_authorization = kwargs.pop('source_authorization', None)
|
3691
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
3692
|
-
mod_conditions = get_modify_conditions(kwargs)
|
3693
|
-
source_mod_conditions = get_source_conditions(kwargs)
|
3694
|
-
cpk_scope_info = get_cpk_scope_info(kwargs)
|
3695
|
-
source_content_md5 = kwargs.pop('source_content_md5', None)
|
3696
|
-
cpk = kwargs.pop('cpk', None)
|
3697
|
-
cpk_info = None
|
3698
|
-
if cpk:
|
3699
|
-
if self.scheme.lower() != 'https':
|
3700
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
3701
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
3702
|
-
encryption_algorithm=cpk.algorithm)
|
3703
|
-
|
3704
|
-
options = {
|
3705
|
-
'copy_source_authorization': source_authorization,
|
3706
|
-
'source_url': source_url,
|
3707
|
-
'content_length': 0,
|
3708
|
-
'source_range': source_range,
|
3709
|
-
'range': destination_range,
|
3710
|
-
'source_content_md5': bytearray(source_content_md5) if source_content_md5 else None,
|
3711
|
-
'timeout': kwargs.pop('timeout', None),
|
3712
|
-
'lease_access_conditions': access_conditions,
|
3713
|
-
'sequence_number_access_conditions': seq_conditions,
|
3714
|
-
'modified_access_conditions': mod_conditions,
|
3715
|
-
'source_modified_access_conditions': source_mod_conditions,
|
3716
|
-
'cpk_scope_info': cpk_scope_info,
|
3717
|
-
'cpk_info': cpk_info,
|
3718
|
-
'cls': return_response_headers}
|
3719
|
-
options.update(kwargs)
|
3720
|
-
return options
|
3721
|
-
|
3722
2793
|
@distributed_trace
|
3723
|
-
def upload_pages_from_url(
|
3724
|
-
|
3725
|
-
|
3726
|
-
|
3727
|
-
|
3728
|
-
|
3729
|
-
|
2794
|
+
def upload_pages_from_url(
|
2795
|
+
self, source_url: str,
|
2796
|
+
offset: int,
|
2797
|
+
length: int,
|
2798
|
+
source_offset: int,
|
2799
|
+
**kwargs: Any
|
2800
|
+
) -> Dict[str, Any]:
|
3730
2801
|
"""
|
3731
2802
|
The Upload Pages operation writes a range of pages to a page blob where
|
3732
2803
|
the contents are read from a URL.
|
@@ -3820,66 +2891,31 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3820
2891
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
3821
2892
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
3822
2893
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
3823
|
-
#other-client--per-operation-configuration>`
|
2894
|
+
#other-client--per-operation-configuration>`__.
|
3824
2895
|
:keyword str source_authorization:
|
3825
2896
|
Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is
|
3826
2897
|
the prefix of the source_authorization string.
|
3827
2898
|
:returns: Response after uploading pages from specified URL.
|
3828
2899
|
:rtype: Dict[str, Any]
|
3829
2900
|
"""
|
3830
|
-
|
3831
|
-
|
2901
|
+
if self.require_encryption or (self.key_encryption_key is not None):
|
2902
|
+
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
2903
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
2904
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
2905
|
+
options = _upload_pages_from_url_options(
|
2906
|
+
source_url=source_url,
|
3832
2907
|
offset=offset,
|
3833
2908
|
length=length,
|
3834
2909
|
source_offset=source_offset,
|
3835
2910
|
**kwargs
|
3836
2911
|
)
|
3837
2912
|
try:
|
3838
|
-
return self._client.page_blob.upload_pages_from_url(**options)
|
2913
|
+
return cast(Dict[str, Any], self._client.page_blob.upload_pages_from_url(**options))
|
3839
2914
|
except HttpResponseError as error:
|
3840
2915
|
process_storage_error(error)
|
3841
2916
|
|
3842
|
-
def _clear_page_options(self, offset, length, **kwargs):
|
3843
|
-
# type: (int, int, **Any) -> Dict[str, Any]
|
3844
|
-
if self.require_encryption or (self.key_encryption_key is not None):
|
3845
|
-
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
3846
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
3847
|
-
seq_conditions = SequenceNumberAccessConditions(
|
3848
|
-
if_sequence_number_less_than_or_equal_to=kwargs.pop('if_sequence_number_lte', None),
|
3849
|
-
if_sequence_number_less_than=kwargs.pop('if_sequence_number_lt', None),
|
3850
|
-
if_sequence_number_equal_to=kwargs.pop('if_sequence_number_eq', None)
|
3851
|
-
)
|
3852
|
-
mod_conditions = get_modify_conditions(kwargs)
|
3853
|
-
if offset is None or offset % 512 != 0:
|
3854
|
-
raise ValueError("offset must be an integer that aligns with 512 page size")
|
3855
|
-
if length is None or length % 512 != 0:
|
3856
|
-
raise ValueError("length must be an integer that aligns with 512 page size")
|
3857
|
-
end_range = length + offset - 1 # Reformat to an inclusive range index
|
3858
|
-
content_range = f'bytes={offset}-{end_range}'
|
3859
|
-
|
3860
|
-
cpk = kwargs.pop('cpk', None)
|
3861
|
-
cpk_info = None
|
3862
|
-
if cpk:
|
3863
|
-
if self.scheme.lower() != 'https':
|
3864
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
3865
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
3866
|
-
encryption_algorithm=cpk.algorithm)
|
3867
|
-
|
3868
|
-
options = {
|
3869
|
-
'content_length': 0,
|
3870
|
-
'timeout': kwargs.pop('timeout', None),
|
3871
|
-
'range': content_range,
|
3872
|
-
'lease_access_conditions': access_conditions,
|
3873
|
-
'sequence_number_access_conditions': seq_conditions,
|
3874
|
-
'modified_access_conditions': mod_conditions,
|
3875
|
-
'cpk_info': cpk_info,
|
3876
|
-
'cls': return_response_headers}
|
3877
|
-
options.update(kwargs)
|
3878
|
-
return options
|
3879
|
-
|
3880
2917
|
@distributed_trace
|
3881
|
-
def clear_page(self, offset, length, **kwargs):
|
3882
|
-
# type: (int, int, **Any) -> Dict[str, Union[str, datetime]]
|
2918
|
+
def clear_page(self, offset: int, length: int, **kwargs: Any) -> Dict[str, Union[str, datetime]]:
|
3883
2919
|
"""Clears a range of pages.
|
3884
2920
|
|
3885
2921
|
:param int offset:
|
@@ -3938,77 +2974,30 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
3938
2974
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
3939
2975
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
3940
2976
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
3941
|
-
#other-client--per-operation-configuration>`
|
2977
|
+
#other-client--per-operation-configuration>`__.
|
3942
2978
|
:returns: Blob-updated property dict (Etag and last modified).
|
3943
2979
|
:rtype: dict(str, Any)
|
3944
2980
|
"""
|
3945
|
-
|
2981
|
+
if self.require_encryption or (self.key_encryption_key is not None):
|
2982
|
+
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
2983
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
2984
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
2985
|
+
options = _clear_page_options(
|
2986
|
+
offset=offset,
|
2987
|
+
length=length,
|
2988
|
+
**kwargs
|
2989
|
+
)
|
3946
2990
|
try:
|
3947
|
-
return self._client.page_blob.clear_pages(**options)
|
2991
|
+
return cast(Dict[str, Any], self._client.page_blob.clear_pages(**options))
|
3948
2992
|
except HttpResponseError as error:
|
3949
2993
|
process_storage_error(error)
|
3950
2994
|
|
3951
|
-
def _append_block_options( # type: ignore
|
3952
|
-
self, data, # type: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]]
|
3953
|
-
length=None, # type: Optional[int]
|
3954
|
-
**kwargs
|
3955
|
-
):
|
3956
|
-
# type: (...) -> Dict[str, Any]
|
3957
|
-
if self.require_encryption or (self.key_encryption_key is not None):
|
3958
|
-
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
3959
|
-
|
3960
|
-
if isinstance(data, str):
|
3961
|
-
data = data.encode(kwargs.pop('encoding', 'UTF-8')) # type: ignore
|
3962
|
-
if length is None:
|
3963
|
-
length = get_length(data)
|
3964
|
-
if length is None:
|
3965
|
-
length, data = read_length(data)
|
3966
|
-
if length == 0:
|
3967
|
-
return {}
|
3968
|
-
if isinstance(data, bytes):
|
3969
|
-
data = data[:length]
|
3970
|
-
|
3971
|
-
appendpos_condition = kwargs.pop('appendpos_condition', None)
|
3972
|
-
maxsize_condition = kwargs.pop('maxsize_condition', None)
|
3973
|
-
validate_content = kwargs.pop('validate_content', False)
|
3974
|
-
append_conditions = None
|
3975
|
-
if maxsize_condition or appendpos_condition is not None:
|
3976
|
-
append_conditions = AppendPositionAccessConditions(
|
3977
|
-
max_size=maxsize_condition,
|
3978
|
-
append_position=appendpos_condition
|
3979
|
-
)
|
3980
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
3981
|
-
mod_conditions = get_modify_conditions(kwargs)
|
3982
|
-
cpk_scope_info = get_cpk_scope_info(kwargs)
|
3983
|
-
cpk = kwargs.pop('cpk', None)
|
3984
|
-
cpk_info = None
|
3985
|
-
if cpk:
|
3986
|
-
if self.scheme.lower() != 'https':
|
3987
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
3988
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
3989
|
-
encryption_algorithm=cpk.algorithm)
|
3990
|
-
options = {
|
3991
|
-
'body': data,
|
3992
|
-
'content_length': length,
|
3993
|
-
'timeout': kwargs.pop('timeout', None),
|
3994
|
-
'transactional_content_md5': None,
|
3995
|
-
'lease_access_conditions': access_conditions,
|
3996
|
-
'append_position_access_conditions': append_conditions,
|
3997
|
-
'modified_access_conditions': mod_conditions,
|
3998
|
-
'validate_content': validate_content,
|
3999
|
-
'cpk_scope_info': cpk_scope_info,
|
4000
|
-
'cpk_info': cpk_info,
|
4001
|
-
'cls': return_response_headers}
|
4002
|
-
options.update(kwargs)
|
4003
|
-
return options
|
4004
|
-
|
4005
2995
|
@distributed_trace
|
4006
|
-
def append_block(
|
4007
|
-
|
4008
|
-
|
4009
|
-
|
4010
|
-
|
4011
|
-
# type: (...) -> Dict[str, Union[str, datetime, int]]
|
2996
|
+
def append_block(
|
2997
|
+
self, data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]],
|
2998
|
+
length: Optional[int] = None,
|
2999
|
+
**kwargs: Any
|
3000
|
+
) -> Dict[str, Union[str, datetime, int]]:
|
4012
3001
|
"""Commits a new block of data to the end of the existing append blob.
|
4013
3002
|
|
4014
3003
|
:param data:
|
@@ -4082,87 +3071,31 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
4082
3071
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
4083
3072
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
4084
3073
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
4085
|
-
#other-client--per-operation-configuration>`
|
3074
|
+
#other-client--per-operation-configuration>`__.
|
4086
3075
|
:returns: Blob-updated property dict (Etag, last modified, append offset, committed block count).
|
4087
3076
|
:rtype: dict(str, Any)
|
4088
3077
|
"""
|
4089
|
-
|
4090
|
-
|
3078
|
+
if self.require_encryption or (self.key_encryption_key is not None):
|
3079
|
+
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
3080
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
3081
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
3082
|
+
options = _append_block_options(
|
3083
|
+
data=data,
|
4091
3084
|
length=length,
|
4092
3085
|
**kwargs
|
4093
3086
|
)
|
4094
3087
|
try:
|
4095
|
-
return self._client.append_blob.append_block(**options)
|
3088
|
+
return cast(Dict[str, Any], self._client.append_blob.append_block(**options))
|
4096
3089
|
except HttpResponseError as error:
|
4097
3090
|
process_storage_error(error)
|
4098
3091
|
|
4099
|
-
def _append_block_from_url_options( # type: ignore
|
4100
|
-
self, copy_source_url, # type: str
|
4101
|
-
source_offset=None, # type: Optional[int]
|
4102
|
-
source_length=None, # type: Optional[int]
|
4103
|
-
**kwargs
|
4104
|
-
):
|
4105
|
-
# type: (...) -> Dict[str, Any]
|
4106
|
-
if self.require_encryption or (self.key_encryption_key is not None):
|
4107
|
-
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
4108
|
-
|
4109
|
-
# If end range is provided, start range must be provided
|
4110
|
-
if source_length is not None and source_offset is None:
|
4111
|
-
raise ValueError("source_offset should also be specified if source_length is specified")
|
4112
|
-
# Format based on whether length is present
|
4113
|
-
source_range = None
|
4114
|
-
if source_length is not None:
|
4115
|
-
end_range = source_offset + source_length - 1
|
4116
|
-
source_range = f'bytes={source_offset}-{end_range}'
|
4117
|
-
elif source_offset is not None:
|
4118
|
-
source_range = f"bytes={source_offset}-"
|
4119
|
-
|
4120
|
-
appendpos_condition = kwargs.pop('appendpos_condition', None)
|
4121
|
-
maxsize_condition = kwargs.pop('maxsize_condition', None)
|
4122
|
-
source_content_md5 = kwargs.pop('source_content_md5', None)
|
4123
|
-
append_conditions = None
|
4124
|
-
if maxsize_condition or appendpos_condition is not None:
|
4125
|
-
append_conditions = AppendPositionAccessConditions(
|
4126
|
-
max_size=maxsize_condition,
|
4127
|
-
append_position=appendpos_condition
|
4128
|
-
)
|
4129
|
-
source_authorization = kwargs.pop('source_authorization', None)
|
4130
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
4131
|
-
mod_conditions = get_modify_conditions(kwargs)
|
4132
|
-
source_mod_conditions = get_source_conditions(kwargs)
|
4133
|
-
cpk_scope_info = get_cpk_scope_info(kwargs)
|
4134
|
-
cpk = kwargs.pop('cpk', None)
|
4135
|
-
cpk_info = None
|
4136
|
-
if cpk:
|
4137
|
-
if self.scheme.lower() != 'https':
|
4138
|
-
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
4139
|
-
cpk_info = CpkInfo(encryption_key=cpk.key_value, encryption_key_sha256=cpk.key_hash,
|
4140
|
-
encryption_algorithm=cpk.algorithm)
|
4141
|
-
|
4142
|
-
options = {
|
4143
|
-
'copy_source_authorization': source_authorization,
|
4144
|
-
'source_url': copy_source_url,
|
4145
|
-
'content_length': 0,
|
4146
|
-
'source_range': source_range,
|
4147
|
-
'source_content_md5': source_content_md5,
|
4148
|
-
'transactional_content_md5': None,
|
4149
|
-
'lease_access_conditions': access_conditions,
|
4150
|
-
'append_position_access_conditions': append_conditions,
|
4151
|
-
'modified_access_conditions': mod_conditions,
|
4152
|
-
'source_modified_access_conditions': source_mod_conditions,
|
4153
|
-
'cpk_scope_info': cpk_scope_info,
|
4154
|
-
'cpk_info': cpk_info,
|
4155
|
-
'cls': return_response_headers,
|
4156
|
-
'timeout': kwargs.pop('timeout', None)}
|
4157
|
-
options.update(kwargs)
|
4158
|
-
return options
|
4159
|
-
|
4160
3092
|
@distributed_trace
|
4161
|
-
def append_block_from_url(
|
4162
|
-
|
4163
|
-
|
4164
|
-
|
4165
|
-
|
3093
|
+
def append_block_from_url(
|
3094
|
+
self, copy_source_url: str,
|
3095
|
+
source_offset: Optional[int] = None,
|
3096
|
+
source_length: Optional[int] = None,
|
3097
|
+
**kwargs: Any
|
3098
|
+
) -> Dict[str, Union[str, datetime, int]]:
|
4166
3099
|
"""
|
4167
3100
|
Creates a new block to be committed as part of a blob, where the contents are read from a source url.
|
4168
3101
|
|
@@ -4250,50 +3183,31 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
4250
3183
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
4251
3184
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
4252
3185
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
4253
|
-
#other-client--per-operation-configuration>`
|
3186
|
+
#other-client--per-operation-configuration>`__.
|
4254
3187
|
:keyword str source_authorization:
|
4255
3188
|
Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is
|
4256
3189
|
the prefix of the source_authorization string.
|
4257
3190
|
:returns: Result after appending a new block.
|
4258
3191
|
:rtype: Dict[str, Union[str, datetime, int]]
|
4259
3192
|
"""
|
4260
|
-
|
4261
|
-
|
3193
|
+
if self.require_encryption or (self.key_encryption_key is not None):
|
3194
|
+
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
3195
|
+
if kwargs.get('cpk') and self.scheme.lower() != 'https':
|
3196
|
+
raise ValueError("Customer provided encryption key must be used over HTTPS.")
|
3197
|
+
options = _append_block_from_url_options(
|
3198
|
+
copy_source_url=copy_source_url,
|
4262
3199
|
source_offset=source_offset,
|
4263
3200
|
source_length=source_length,
|
4264
3201
|
**kwargs
|
4265
3202
|
)
|
4266
3203
|
try:
|
4267
|
-
return
|
3204
|
+
return cast(Dict[str, Union[str, datetime, int]],
|
3205
|
+
self._client.append_blob.append_block_from_url(**options))
|
4268
3206
|
except HttpResponseError as error:
|
4269
3207
|
process_storage_error(error)
|
4270
3208
|
|
4271
|
-
def _seal_append_blob_options(self, **kwargs):
|
4272
|
-
# type: (...) -> Dict[str, Any]
|
4273
|
-
if self.require_encryption or (self.key_encryption_key is not None):
|
4274
|
-
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
4275
|
-
|
4276
|
-
appendpos_condition = kwargs.pop('appendpos_condition', None)
|
4277
|
-
append_conditions = None
|
4278
|
-
if appendpos_condition is not None:
|
4279
|
-
append_conditions = AppendPositionAccessConditions(
|
4280
|
-
append_position=appendpos_condition
|
4281
|
-
)
|
4282
|
-
access_conditions = get_access_conditions(kwargs.pop('lease', None))
|
4283
|
-
mod_conditions = get_modify_conditions(kwargs)
|
4284
|
-
|
4285
|
-
options = {
|
4286
|
-
'timeout': kwargs.pop('timeout', None),
|
4287
|
-
'lease_access_conditions': access_conditions,
|
4288
|
-
'append_position_access_conditions': append_conditions,
|
4289
|
-
'modified_access_conditions': mod_conditions,
|
4290
|
-
'cls': return_response_headers}
|
4291
|
-
options.update(kwargs)
|
4292
|
-
return options
|
4293
|
-
|
4294
3209
|
@distributed_trace
|
4295
|
-
def seal_append_blob(self, **kwargs):
|
4296
|
-
# type: (...) -> Dict[str, Union[str, datetime, int]]
|
3210
|
+
def seal_append_blob(self, **kwargs: Any) -> Dict[str, Union[str, datetime, int]]:
|
4297
3211
|
"""The Seal operation seals the Append Blob to make it read-only.
|
4298
3212
|
|
4299
3213
|
.. versionadded:: 12.4.0
|
@@ -4330,19 +3244,20 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
4330
3244
|
https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-blob-service-operations.
|
4331
3245
|
This value is not tracked or validated on the client. To configure client-side network timesouts
|
4332
3246
|
see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
|
4333
|
-
#other-client--per-operation-configuration>`
|
3247
|
+
#other-client--per-operation-configuration>`__.
|
4334
3248
|
:returns: Blob-updated property dict (Etag, last modified, append offset, committed block count).
|
4335
3249
|
:rtype: dict(str, Any)
|
4336
3250
|
"""
|
4337
|
-
|
3251
|
+
if self.require_encryption or (self.key_encryption_key is not None):
|
3252
|
+
raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
|
3253
|
+
options = _seal_append_blob_options(**kwargs)
|
4338
3254
|
try:
|
4339
|
-
return self._client.append_blob.seal(**options)
|
3255
|
+
return cast(Dict[str, Any], self._client.append_blob.seal(**options))
|
4340
3256
|
except HttpResponseError as error:
|
4341
3257
|
process_storage_error(error)
|
4342
3258
|
|
4343
3259
|
@distributed_trace
|
4344
|
-
def _get_container_client(self)
|
4345
|
-
# type: (...) -> ContainerClient
|
3260
|
+
def _get_container_client(self) -> "ContainerClient":
|
4346
3261
|
"""Get a client to interact with the blob's parent container.
|
4347
3262
|
|
4348
3263
|
The container need not already exist. Defaults to current blob's credentials.
|
@@ -4366,7 +3281,7 @@ class BlobClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: d
|
|
4366
3281
|
policies=self._pipeline._impl_policies # pylint: disable = protected-access
|
4367
3282
|
)
|
4368
3283
|
else:
|
4369
|
-
_pipeline = self._pipeline
|
3284
|
+
_pipeline = self._pipeline # pylint: disable = protected-access
|
4370
3285
|
return ContainerClient(
|
4371
3286
|
f"{self.scheme}://{self.primary_hostname}", container_name=self.container_name,
|
4372
3287
|
credential=self._raw_credential, api_version=self.api_version, _configuration=self._config,
|