azure-storage-blob 12.21.0__py3-none-any.whl → 12.22.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. azure/storage/blob/__init__.py +19 -18
  2. azure/storage/blob/_blob_client.py +417 -1507
  3. azure/storage/blob/_blob_client_helpers.py +1242 -0
  4. azure/storage/blob/_blob_service_client.py +82 -101
  5. azure/storage/blob/_blob_service_client_helpers.py +27 -0
  6. azure/storage/blob/_container_client.py +147 -356
  7. azure/storage/blob/_container_client_helpers.py +261 -0
  8. azure/storage/blob/_deserialize.py +68 -44
  9. azure/storage/blob/_download.py +114 -90
  10. azure/storage/blob/_encryption.py +14 -7
  11. azure/storage/blob/_lease.py +47 -58
  12. azure/storage/blob/_list_blobs_helper.py +129 -135
  13. azure/storage/blob/_models.py +479 -276
  14. azure/storage/blob/_quick_query_helper.py +30 -31
  15. azure/storage/blob/_serialize.py +38 -56
  16. azure/storage/blob/_shared/avro/datafile.py +1 -1
  17. azure/storage/blob/_shared/avro/datafile_async.py +1 -1
  18. azure/storage/blob/_shared/base_client.py +1 -1
  19. azure/storage/blob/_shared/base_client_async.py +1 -1
  20. azure/storage/blob/_shared/policies.py +8 -6
  21. azure/storage/blob/_shared/policies_async.py +3 -1
  22. azure/storage/blob/_shared/response_handlers.py +6 -2
  23. azure/storage/blob/_shared/shared_access_signature.py +2 -2
  24. azure/storage/blob/_shared/uploads.py +1 -1
  25. azure/storage/blob/_shared/uploads_async.py +1 -1
  26. azure/storage/blob/_shared_access_signature.py +70 -53
  27. azure/storage/blob/_upload_helpers.py +75 -68
  28. azure/storage/blob/_version.py +1 -1
  29. azure/storage/blob/aio/__init__.py +19 -11
  30. azure/storage/blob/aio/_blob_client_async.py +505 -255
  31. azure/storage/blob/aio/_blob_service_client_async.py +138 -87
  32. azure/storage/blob/aio/_container_client_async.py +260 -120
  33. azure/storage/blob/aio/_download_async.py +104 -87
  34. azure/storage/blob/aio/_lease_async.py +56 -55
  35. azure/storage/blob/aio/_list_blobs_helper.py +94 -96
  36. azure/storage/blob/aio/_models.py +60 -38
  37. azure/storage/blob/aio/_upload_helpers.py +75 -66
  38. {azure_storage_blob-12.21.0.dist-info → azure_storage_blob-12.22.0.dist-info}/METADATA +1 -1
  39. {azure_storage_blob-12.21.0.dist-info → azure_storage_blob-12.22.0.dist-info}/RECORD +42 -39
  40. {azure_storage_blob-12.21.0.dist-info → azure_storage_blob-12.22.0.dist-info}/LICENSE +0 -0
  41. {azure_storage_blob-12.21.0.dist-info → azure_storage_blob-12.22.0.dist-info}/WHEEL +0 -0
  42. {azure_storage_blob-12.21.0.dist-info → azure_storage_blob-12.22.0.dist-info}/top_level.txt +0 -0
@@ -6,11 +6,13 @@
6
6
  # pylint: disable=too-many-lines, invalid-overridden-method, docstring-keyword-should-match-keyword-only
7
7
 
8
8
  import warnings
9
+ from datetime import datetime
9
10
  from functools import partial
10
- from typing import ( # pylint: disable=unused-import
11
- Any, AnyStr, AsyncIterable, Dict, IO, Iterable, List, Optional, overload, Tuple, Union,
11
+ from typing import (
12
+ Any, AnyStr, AsyncIterable, cast, Dict, IO, Iterable, List, Optional, overload, Tuple, Union,
12
13
  TYPE_CHECKING
13
14
  )
15
+ from typing_extensions import Self
14
16
 
15
17
  from azure.core.async_paging import AsyncItemPaged
16
18
  from azure.core.exceptions import ResourceNotFoundError, HttpResponseError, ResourceExistsError
@@ -18,44 +20,76 @@ from azure.core.pipeline import AsyncPipeline
18
20
  from azure.core.tracing.decorator import distributed_trace
19
21
  from azure.core.tracing.decorator_async import distributed_trace_async
20
22
 
21
- from .._shared.base_client_async import AsyncStorageAccountHostsMixin, AsyncTransportWrapper
22
- from .._shared.policies_async import ExponentialRetry
23
- from .._shared.response_handlers import return_response_headers, process_storage_error
24
- from .._generated.aio import AzureBlobStorage
25
- from .._generated.models import CpkInfo
26
- from .._blob_client import BlobClient as BlobClientBase
27
- from .._deserialize import (
28
- deserialize_blob_properties,
29
- deserialize_pipeline_response_into_cls,
30
- get_page_ranges_result,
31
- parse_tags
32
- )
33
- from .._encryption import StorageEncryptionMixin
34
- from .._models import BlobType, BlobBlock, BlobProperties, PageRange
35
- from .._serialize import get_modify_conditions, get_api_version, get_access_conditions, get_version_id
36
23
  from ._download_async import StorageStreamDownloader
37
24
  from ._lease_async import BlobLeaseClient
38
25
  from ._models import PageRangePaged
39
26
  from ._upload_helpers import (
40
- upload_block_blob,
41
27
  upload_append_blob,
28
+ upload_block_blob,
42
29
  upload_page_blob
43
30
  )
31
+ from .._blob_client import StorageAccountHostsMixin
32
+ from .._blob_client_helpers import (
33
+ _abort_copy_options,
34
+ _append_block_from_url_options,
35
+ _append_block_options,
36
+ _clear_page_options,
37
+ _commit_block_list_options,
38
+ _create_append_blob_options,
39
+ _create_page_blob_options,
40
+ _create_snapshot_options,
41
+ _delete_blob_options,
42
+ _download_blob_options,
43
+ _format_url,
44
+ _from_blob_url,
45
+ _get_blob_tags_options,
46
+ _get_block_list_result,
47
+ _get_page_ranges_options,
48
+ _parse_url,
49
+ _resize_blob_options,
50
+ _seal_append_blob_options,
51
+ _set_blob_metadata_options,
52
+ _set_blob_tags_options,
53
+ _set_http_headers_options,
54
+ _set_sequence_number_options,
55
+ _stage_block_from_url_options,
56
+ _stage_block_options,
57
+ _start_copy_from_url_options,
58
+ _upload_blob_from_url_options,
59
+ _upload_blob_options,
60
+ _upload_page_options,
61
+ _upload_pages_from_url_options
62
+ )
63
+ from .._deserialize import (
64
+ deserialize_blob_properties,
65
+ deserialize_pipeline_response_into_cls,
66
+ get_page_ranges_result,
67
+ parse_tags
68
+ )
69
+ from .._encryption import StorageEncryptionMixin, _ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION
70
+ from .._generated.aio import AzureBlobStorage
71
+ from .._generated.models import CpkInfo
72
+ from .._models import BlobType, BlobBlock, BlobProperties, PageRange
73
+ from .._serialize import get_access_conditions, get_api_version, get_modify_conditions, get_version_id
74
+ from .._shared.base_client_async import AsyncStorageAccountHostsMixin, AsyncTransportWrapper, parse_connection_str
75
+ from .._shared.policies_async import ExponentialRetry
76
+ from .._shared.response_handlers import process_storage_error, return_response_headers
44
77
 
45
78
  if TYPE_CHECKING:
46
79
  from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential
47
80
  from azure.core.credentials_async import AsyncTokenCredential
48
- from datetime import datetime
49
- from .._models import ( # pylint: disable=unused-import
81
+ from azure.core.pipeline.policies import AsyncHTTPPolicy
82
+ from azure.storage.blob.aio import ContainerClient
83
+ from .._models import (
50
84
  ContentSettings,
51
85
  ImmutabilityPolicy,
52
86
  PremiumPageBlobTier,
53
- StandardBlobTier,
54
- SequenceNumberAction
87
+ SequenceNumberAction,
88
+ StandardBlobTier
55
89
  )
56
90
 
57
91
 
58
- class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptionMixin): # pylint: disable=too-many-public-methods
92
+ class BlobClient(AsyncStorageAccountHostsMixin, StorageAccountHostsMixin, StorageEncryptionMixin): # type: ignore [misc] # pylint: disable=too-many-public-methods
59
93
  """A client to interact with a specific blob, although that blob may not yet exist.
60
94
 
61
95
  :param str account_url:
@@ -128,22 +162,139 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
128
162
  snapshot: Optional[Union[str, Dict[str, Any]]] = None,
129
163
  credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long
130
164
  **kwargs: Any
131
- ) -> None:
165
+ ) -> None:
132
166
  kwargs['retry_policy'] = kwargs.get('retry_policy') or ExponentialRetry(**kwargs)
133
- super(BlobClient, self).__init__(
134
- account_url,
167
+ parsed_url, sas_token, path_snapshot = _parse_url(
168
+ account_url=account_url,
135
169
  container_name=container_name,
136
- blob_name=blob_name,
137
- snapshot=snapshot,
138
- credential=credential,
139
- **kwargs)
170
+ blob_name=blob_name)
171
+ self.container_name = container_name
172
+ self.blob_name = blob_name
173
+
174
+ if snapshot is not None and hasattr(snapshot, 'snapshot'):
175
+ self.snapshot = snapshot.snapshot
176
+ elif isinstance(snapshot, dict):
177
+ self.snapshot = snapshot['snapshot']
178
+ else:
179
+ self.snapshot = snapshot or path_snapshot
180
+ self.version_id = kwargs.pop('version_id', None)
181
+
182
+ # This parameter is used for the hierarchy traversal. Give precedence to credential.
183
+ self._raw_credential = credential if credential else sas_token
184
+ self._query_str, credential = self._format_query_string(sas_token, credential, snapshot=self.snapshot)
185
+ super(BlobClient, self).__init__(parsed_url, service='blob', credential=credential, **kwargs)
140
186
  self._client = AzureBlobStorage(self.url, base_url=self.url, pipeline=self._pipeline)
141
- self._client._config.version = get_api_version(kwargs) # pylint: disable=protected-access
187
+ self._client._config.version = get_api_version(kwargs) # type: ignore [assignment] # pylint: disable=protected-access
142
188
  self._configure_encryption(kwargs)
143
189
 
190
+ def _format_url(self, hostname: str) -> str:
191
+ return _format_url(
192
+ container_name=self.container_name,
193
+ scheme=self.scheme,
194
+ blob_name=self.blob_name,
195
+ query_str=self._query_str,
196
+ hostname=hostname
197
+ )
198
+
199
+ @classmethod
200
+ def from_blob_url(
201
+ cls, blob_url: str,
202
+ credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long
203
+ snapshot: Optional[Union[str, Dict[str, Any]]] = None,
204
+ **kwargs: Any
205
+ ) -> Self:
206
+ """Create BlobClient from a blob url. This doesn't support customized blob url with '/' in blob name.
207
+
208
+ :param str blob_url:
209
+ The full endpoint URL to the Blob, including SAS token and snapshot if used. This could be
210
+ either the primary endpoint, or the secondary endpoint depending on the current `location_mode`.
211
+ :type blob_url: str
212
+ :param credential:
213
+ The credentials with which to authenticate. This is optional if the
214
+ account URL already has a SAS token, or the connection string already has shared
215
+ access key values. The value can be a SAS token string,
216
+ an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials,
217
+ an account shared access key, or an instance of a TokenCredentials class from azure.identity.
218
+ If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential
219
+ - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError.
220
+ If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key"
221
+ should be the storage account key.
222
+ :type credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] # pylint: disable=line-too-long
223
+ :param str snapshot:
224
+ The optional blob snapshot on which to operate. This can be the snapshot ID string
225
+ or the response returned from :func:`create_snapshot`. If specified, this will override
226
+ the snapshot in the url.
227
+ :keyword str version_id: The version id parameter is an opaque DateTime value that, when present,
228
+ specifies the version of the blob to operate on.
229
+ :keyword str audience: The audience to use when requesting tokens for Azure Active Directory
230
+ authentication. Only has an effect when credential is of type TokenCredential. The value could be
231
+ https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net.
232
+ :returns: A Blob client.
233
+ :rtype: ~azure.storage.blob.BlobClient
234
+ """
235
+ account_url, container_name, blob_name, path_snapshot = _from_blob_url(blob_url=blob_url, snapshot=snapshot)
236
+ return cls(
237
+ account_url, container_name=container_name, blob_name=blob_name,
238
+ snapshot=path_snapshot, credential=credential, **kwargs
239
+ )
240
+
241
+ @classmethod
242
+ def from_connection_string(
243
+ cls, conn_str: str,
244
+ container_name: str,
245
+ blob_name: str,
246
+ snapshot: Optional[Union[str, Dict[str, Any]]] = None,
247
+ credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long
248
+ **kwargs: Any
249
+ ) -> Self:
250
+ """Create BlobClient from a Connection String.
251
+
252
+ :param str conn_str:
253
+ A connection string to an Azure Storage account.
254
+ :param container_name: The container name for the blob.
255
+ :type container_name: str
256
+ :param blob_name: The name of the blob with which to interact.
257
+ :type blob_name: str
258
+ :param str snapshot:
259
+ The optional blob snapshot on which to operate. This can be the snapshot ID string
260
+ or the response returned from :func:`create_snapshot`.
261
+ :param credential:
262
+ The credentials with which to authenticate. This is optional if the
263
+ account URL already has a SAS token, or the connection string already has shared
264
+ access key values. The value can be a SAS token string,
265
+ an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials,
266
+ an account shared access key, or an instance of a TokenCredentials class from azure.identity.
267
+ Credentials provided here will take precedence over those in the connection string.
268
+ If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key"
269
+ should be the storage account key.
270
+ :type credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] # pylint: disable=line-too-long
271
+ :keyword str version_id: The version id parameter is an opaque DateTime value that, when present,
272
+ specifies the version of the blob to operate on.
273
+ :keyword str audience: The audience to use when requesting tokens for Azure Active Directory
274
+ authentication. Only has an effect when credential is of type TokenCredential. The value could be
275
+ https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net.
276
+ :returns: A Blob client.
277
+ :rtype: ~azure.storage.blob.BlobClient
278
+
279
+ .. admonition:: Example:
280
+
281
+ .. literalinclude:: ../samples/blob_samples_authentication.py
282
+ :start-after: [START auth_from_connection_string_blob]
283
+ :end-before: [END auth_from_connection_string_blob]
284
+ :language: python
285
+ :dedent: 8
286
+ :caption: Creating the BlobClient from a connection string.
287
+ """
288
+ account_url, secondary, credential = parse_connection_str(conn_str, credential, 'blob')
289
+ if 'secondary_hostname' not in kwargs:
290
+ kwargs['secondary_hostname'] = secondary
291
+ return cls(
292
+ account_url, container_name=container_name, blob_name=blob_name,
293
+ snapshot=snapshot, credential=credential, **kwargs
294
+ )
295
+
144
296
  @distributed_trace_async
145
- async def get_account_information(self, **kwargs): # type: ignore
146
- # type: (Optional[int]) -> Dict[str, str]
297
+ async def get_account_information(self, **kwargs: Any) -> Dict[str, str]:
147
298
  """Gets information related to the storage account in which the blob resides.
148
299
 
149
300
  The information can also be retrieved if the user has a SAS to a container or blob.
@@ -153,13 +304,13 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
153
304
  :rtype: dict(str, str)
154
305
  """
155
306
  try:
156
- return await self._client.blob.get_account_info(cls=return_response_headers, **kwargs) # type: ignore
307
+ return cast(Dict[str, str],
308
+ await self._client.blob.get_account_info(cls=return_response_headers, **kwargs))
157
309
  except HttpResponseError as error:
158
310
  process_storage_error(error)
159
311
 
160
312
  @distributed_trace_async
161
- async def upload_blob_from_url(self, source_url, **kwargs):
162
- # type: (str, Any) -> Dict[str, Any]
313
+ async def upload_blob_from_url(self, source_url: str, **kwargs: Any) -> Dict[str, Any]:
163
314
  """
164
315
  Creates a new Block Blob where the content of the blob is read from a given URL.
165
316
  The content of an existing blob is overwritten with the new blob.
@@ -257,25 +408,28 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
257
408
  :returns: Response from creating a new block blob for a given URL.
258
409
  :rtype: Dict[str, Any]
259
410
  """
260
- options = self._upload_blob_from_url_options(
261
- source_url=self._encode_source_url(source_url),
411
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
412
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
413
+ options = _upload_blob_from_url_options(
414
+ source_url=source_url,
262
415
  **kwargs)
263
416
  try:
264
- return await self._client.block_blob.put_blob_from_url(**options)
417
+ return cast(Dict[str, Any], await self._client.block_blob.put_blob_from_url(**options))
265
418
  except HttpResponseError as error:
266
419
  process_storage_error(error)
267
420
 
268
421
  @distributed_trace_async
269
422
  async def upload_blob(
270
- self, data: Union[bytes, str, Iterable[AnyStr], AsyncIterable[AnyStr], IO[AnyStr]],
271
- blob_type: Union[str, BlobType] = BlobType.BlockBlob,
272
- length: Optional[int] = None,
273
- metadata: Optional[Dict[str, str]] = None,
274
- **kwargs
275
- ) -> Dict[str, Any]:
423
+ self, data: Union[bytes, str, Iterable[AnyStr], AsyncIterable[AnyStr], IO[bytes]],
424
+ blob_type: Union[str, BlobType] = BlobType.BLOCKBLOB,
425
+ length: Optional[int] = None,
426
+ metadata: Optional[Dict[str, str]] = None,
427
+ **kwargs: Any
428
+ ) -> Dict[str, Any]:
276
429
  """Creates a new blob from a data source with automatic chunking.
277
430
 
278
431
  :param data: The blob data to upload.
432
+ :type data: Union[bytes, str, Iterable[AnyStr], AsyncIterable[AnyStr], IO[AnyStr]]
279
433
  :param ~azure.storage.blob.BlobType blob_type: The type of the blob. This can be
280
434
  either BlockBlob, PageBlob or AppendBlob. The default value is BlockBlob.
281
435
  :param int length:
@@ -411,43 +565,59 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
411
565
  :dedent: 16
412
566
  :caption: Upload a blob to the container.
413
567
  """
414
- options = self._upload_blob_options(
415
- data,
568
+ if self.require_encryption and not self.key_encryption_key:
569
+ raise ValueError("Encryption required but no key was provided.")
570
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
571
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
572
+ options = _upload_blob_options(
573
+ data=data,
416
574
  blob_type=blob_type,
417
575
  length=length,
418
576
  metadata=metadata,
577
+ encryption_options={
578
+ 'required': self.require_encryption,
579
+ 'version': self.encryption_version,
580
+ 'key': self.key_encryption_key,
581
+ 'resolver': self.key_resolver_function
582
+ },
583
+ config=self._config,
584
+ sdk_moniker=self._sdk_moniker,
585
+ client=self._client,
419
586
  **kwargs)
420
587
  if blob_type == BlobType.BlockBlob:
421
- return await upload_block_blob(**options)
588
+ return cast(Dict[str, Any], await upload_block_blob(**options))
422
589
  if blob_type == BlobType.PageBlob:
423
- return await upload_page_blob(**options)
424
- return await upload_append_blob(**options)
590
+ return cast(Dict[str, Any], await upload_page_blob(**options))
591
+ return cast(Dict[str, Any], await upload_append_blob(**options))
425
592
 
426
593
  @overload
427
594
  async def download_blob(
428
- self, offset: int = None,
429
- length: int = None,
430
- *,
431
- encoding: str,
432
- **kwargs) -> StorageStreamDownloader[str]:
595
+ self, offset: Optional[int] = None,
596
+ length: Optional[int] = None,
597
+ *,
598
+ encoding: str,
599
+ **kwargs: Any
600
+ ) -> StorageStreamDownloader[str]:
433
601
  ...
434
602
 
435
603
  @overload
436
604
  async def download_blob(
437
- self, offset: int = None,
438
- length: int = None,
439
- *,
440
- encoding: None = None,
441
- **kwargs) -> StorageStreamDownloader[bytes]:
605
+ self, offset: Optional[int] = None,
606
+ length: Optional[int] = None,
607
+ *,
608
+ encoding: None = None,
609
+ **kwargs: Any
610
+ ) -> StorageStreamDownloader[bytes]:
442
611
  ...
443
612
 
444
613
  @distributed_trace_async
445
614
  async def download_blob(
446
- self, offset: int = None,
447
- length: int = None,
448
- *,
449
- encoding: Optional[str] = None,
450
- **kwargs) -> StorageStreamDownloader:
615
+ self, offset: Optional[int] = None,
616
+ length: Optional[int] = None,
617
+ *,
618
+ encoding: Union[str, None] = None,
619
+ **kwargs: Any
620
+ ) -> Union[StorageStreamDownloader[str], StorageStreamDownloader[bytes]]:
451
621
  """Downloads a blob to the StorageStreamDownloader. The readall() method must
452
622
  be used to read all the content or readinto() must be used to download the blob into
453
623
  a stream. Using chunks() returns an async iterator which allows the user to iterate over the content in chunks.
@@ -538,18 +708,35 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
538
708
  :dedent: 16
539
709
  :caption: Download a blob.
540
710
  """
541
- options = self._download_blob_options(
711
+ if self.require_encryption and not (self.key_encryption_key or self.key_resolver_function):
712
+ raise ValueError("Encryption required but no key was provided.")
713
+ if length is not None and offset is None:
714
+ raise ValueError("Offset value must not be None if length is set.")
715
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
716
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
717
+ options = _download_blob_options(
718
+ blob_name=self.blob_name,
719
+ container_name=self.container_name,
720
+ version_id=get_version_id(self.version_id, kwargs),
542
721
  offset=offset,
543
722
  length=length,
544
723
  encoding=encoding,
724
+ encryption_options={
725
+ 'required': self.require_encryption,
726
+ 'version': self.encryption_version,
727
+ 'key': self.key_encryption_key,
728
+ 'resolver': self.key_resolver_function
729
+ },
730
+ config=self._config,
731
+ sdk_moniker=self._sdk_moniker,
732
+ client=self._client,
545
733
  **kwargs)
546
734
  downloader = StorageStreamDownloader(**options)
547
735
  await downloader._setup() # pylint: disable=protected-access
548
736
  return downloader
549
737
 
550
738
  @distributed_trace_async
551
- async def delete_blob(self, delete_snapshots=None, **kwargs):
552
- # type: (str, Any) -> None
739
+ async def delete_blob(self, delete_snapshots: Optional[str] = None, **kwargs: Any) -> None:
553
740
  """Marks the specified blob for deletion.
554
741
 
555
742
  The blob is later deleted during garbage collection.
@@ -620,15 +807,18 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
620
807
  :dedent: 16
621
808
  :caption: Delete a blob.
622
809
  """
623
- options = self._delete_blob_options(delete_snapshots=delete_snapshots, **kwargs)
810
+ options = _delete_blob_options(
811
+ snapshot=self.snapshot,
812
+ version_id=get_version_id(self.version_id, kwargs),
813
+ delete_snapshots=delete_snapshots,
814
+ **kwargs)
624
815
  try:
625
816
  await self._client.blob.delete(**options)
626
817
  except HttpResponseError as error:
627
818
  process_storage_error(error)
628
819
 
629
820
  @distributed_trace_async
630
- async def undelete_blob(self, **kwargs):
631
- # type: (Any) -> None
821
+ async def undelete_blob(self, **kwargs: Any) -> None:
632
822
  """Restores soft-deleted blobs or snapshots.
633
823
 
634
824
  Operation will only be successful if used within the specified number of days
@@ -661,8 +851,7 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
661
851
  process_storage_error(error)
662
852
 
663
853
  @distributed_trace_async
664
- async def exists(self, **kwargs):
665
- # type: (**Any) -> bool
854
+ async def exists(self, **kwargs: Any) -> bool:
666
855
  """
667
856
  Returns True if a blob exists with the defined parameters, and returns
668
857
  False otherwise.
@@ -696,8 +885,7 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
696
885
  return False
697
886
 
698
887
  @distributed_trace_async
699
- async def get_blob_properties(self, **kwargs):
700
- # type: (Any) -> BlobProperties
888
+ async def get_blob_properties(self, **kwargs: Any) -> BlobProperties:
701
889
  """Returns all user-defined metadata, standard HTTP properties, and
702
890
  system properties for the blob. It does not return the content of the blob.
703
891
 
@@ -788,11 +976,13 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
788
976
  if isinstance(blob_props, BlobProperties):
789
977
  blob_props.container = self.container_name
790
978
  blob_props.snapshot = self.snapshot
791
- return blob_props # type: ignore
979
+ return cast(BlobProperties, blob_props)
792
980
 
793
981
  @distributed_trace_async
794
- async def set_http_headers(self, content_settings=None, **kwargs):
795
- # type: (Optional[ContentSettings], Any) -> None
982
+ async def set_http_headers(
983
+ self, content_settings: Optional["ContentSettings"] = None,
984
+ **kwargs: Any
985
+ ) -> Dict[str, Any]:
796
986
  """Sets system properties on the blob.
797
987
 
798
988
  If one property is set for the content_settings, all properties will be overridden.
@@ -836,15 +1026,17 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
836
1026
  :returns: Blob-updated property dict (Etag and last modified)
837
1027
  :rtype: Dict[str, Any]
838
1028
  """
839
- options = self._set_http_headers_options(content_settings=content_settings, **kwargs)
1029
+ options = _set_http_headers_options(content_settings=content_settings, **kwargs)
840
1030
  try:
841
- return await self._client.blob.set_http_headers(**options) # type: ignore
1031
+ return cast(Dict[str, Any], await self._client.blob.set_http_headers(**options))
842
1032
  except HttpResponseError as error:
843
1033
  process_storage_error(error)
844
1034
 
845
1035
  @distributed_trace_async
846
- async def set_blob_metadata(self, metadata=None, **kwargs):
847
- # type: (Optional[Dict[str, str]], Any) -> Dict[str, Union[str, datetime]]
1036
+ async def set_blob_metadata(
1037
+ self, metadata: Optional[Dict[str, str]] = None,
1038
+ **kwargs: Any
1039
+ ) -> Dict[str, Union[str, datetime]]:
848
1040
  """Sets user-defined metadata for the blob as one or more name-value pairs.
849
1041
 
850
1042
  :param metadata:
@@ -901,15 +1093,19 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
901
1093
  :returns: Blob-updated property dict (Etag and last modified)
902
1094
  :rtype: Dict[str, Union[str, datetime]]
903
1095
  """
904
- options = self._set_blob_metadata_options(metadata=metadata, **kwargs)
1096
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
1097
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
1098
+ options = _set_blob_metadata_options(metadata=metadata, **kwargs)
905
1099
  try:
906
- return await self._client.blob.set_metadata(**options) # type: ignore
1100
+ return cast(Dict[str, Union[str, datetime]], await self._client.blob.set_metadata(**options))
907
1101
  except HttpResponseError as error:
908
1102
  process_storage_error(error)
909
1103
 
910
1104
  @distributed_trace_async
911
- async def set_immutability_policy(self, immutability_policy, **kwargs):
912
- # type: (ImmutabilityPolicy, **Any) -> Dict[str, str]
1105
+ async def set_immutability_policy(
1106
+ self, immutability_policy: "ImmutabilityPolicy",
1107
+ **kwargs: Any
1108
+ ) -> Dict[str, str]:
913
1109
  """The Set Immutability Policy operation sets the immutability policy on the blob.
914
1110
 
915
1111
  .. versionadded:: 12.10.0
@@ -933,11 +1129,11 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
933
1129
 
934
1130
  kwargs['immutability_policy_expiry'] = immutability_policy.expiry_time
935
1131
  kwargs['immutability_policy_mode'] = immutability_policy.policy_mode
936
- return await self._client.blob.set_immutability_policy(cls=return_response_headers, **kwargs)
1132
+ return cast(Dict[str, str],
1133
+ await self._client.blob.set_immutability_policy(cls=return_response_headers, **kwargs))
937
1134
 
938
1135
  @distributed_trace_async
939
- async def delete_immutability_policy(self, **kwargs):
940
- # type: (**Any) -> None
1136
+ async def delete_immutability_policy(self, **kwargs: Any) -> None:
941
1137
  """The Delete Immutability Policy operation deletes the immutability policy on the blob.
942
1138
 
943
1139
  .. versionadded:: 12.10.0
@@ -956,8 +1152,7 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
956
1152
  await self._client.blob.delete_immutability_policy(**kwargs)
957
1153
 
958
1154
  @distributed_trace_async
959
- async def set_legal_hold(self, legal_hold, **kwargs):
960
- # type: (bool, **Any) -> Dict[str, Union[str, datetime, bool]]
1155
+ async def set_legal_hold(self, legal_hold: bool, **kwargs: Any) -> Dict[str, Union[str, datetime, bool]]:
961
1156
  """The Set Legal Hold operation sets a legal hold on the blob.
962
1157
 
963
1158
  .. versionadded:: 12.10.0
@@ -975,17 +1170,17 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
975
1170
  :rtype: Dict[str, Union[str, datetime, bool]]
976
1171
  """
977
1172
 
978
- return await self._client.blob.set_legal_hold(legal_hold, cls=return_response_headers, **kwargs)
1173
+ return cast(Dict[str, Union[str, datetime, bool]],
1174
+ await self._client.blob.set_legal_hold(legal_hold, cls=return_response_headers, **kwargs))
979
1175
 
980
1176
  @distributed_trace_async
981
- async def create_page_blob( # type: ignore
982
- self, size, # type: int
983
- content_settings=None, # type: Optional[ContentSettings]
984
- metadata=None, # type: Optional[Dict[str, str]]
985
- premium_page_blob_tier=None, # type: Optional[Union[str, PremiumPageBlobTier]]
986
- **kwargs
987
- ):
988
- # type: (...) -> Dict[str, Union[str, datetime]]
1177
+ async def create_page_blob(
1178
+ self, size: int,
1179
+ content_settings: Optional["ContentSettings"] = None,
1180
+ metadata: Optional[Dict[str, str]] = None,
1181
+ premium_page_blob_tier: Optional[Union[str, "PremiumPageBlobTier"]] = None,
1182
+ **kwargs: Any
1183
+ ) -> Dict[str, Union[str, datetime]]:
989
1184
  """Creates a new Page Blob of the specified size.
990
1185
 
991
1186
  :param int size:
@@ -1070,20 +1265,27 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1070
1265
  :returns: Blob-updated property dict (Etag and last modified).
1071
1266
  :rtype: dict[str, Any]
1072
1267
  """
1073
- options = self._create_page_blob_options(
1074
- size,
1268
+ if self.require_encryption or (self.key_encryption_key is not None):
1269
+ raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
1270
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
1271
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
1272
+ options = _create_page_blob_options(
1273
+ size=size,
1075
1274
  content_settings=content_settings,
1076
1275
  metadata=metadata,
1077
1276
  premium_page_blob_tier=premium_page_blob_tier,
1078
1277
  **kwargs)
1079
1278
  try:
1080
- return await self._client.page_blob.create(**options) # type: ignore
1279
+ return cast(Dict[str, Any], await self._client.page_blob.create(**options))
1081
1280
  except HttpResponseError as error:
1082
1281
  process_storage_error(error)
1083
1282
 
1084
1283
  @distributed_trace_async
1085
- async def create_append_blob(self, content_settings=None, metadata=None, **kwargs):
1086
- # type: (Optional[ContentSettings], Optional[Dict[str, str]], Any) -> Dict[str, Union[str, datetime]]
1284
+ async def create_append_blob(
1285
+ self, content_settings: Optional["ContentSettings"] = None,
1286
+ metadata: Optional[Dict[str, str]] = None,
1287
+ **kwargs: Any
1288
+ ) -> Dict[str, Union[str, datetime]]:
1087
1289
  """Creates a new Append Blob. This operation creates a new 0-length append blob. The content
1088
1290
  of any existing blob is overwritten with the newly initialized append blob. To add content to
1089
1291
  the append blob, call the :func:`append_block` or :func:`append_block_from_url` method.
@@ -1159,18 +1361,24 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1159
1361
  :returns: Blob-updated property dict (Etag and last modified).
1160
1362
  :rtype: dict[str, Any]
1161
1363
  """
1162
- options = self._create_append_blob_options(
1364
+ if self.require_encryption or (self.key_encryption_key is not None):
1365
+ raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
1366
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
1367
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
1368
+ options = _create_append_blob_options(
1163
1369
  content_settings=content_settings,
1164
1370
  metadata=metadata,
1165
1371
  **kwargs)
1166
1372
  try:
1167
- return await self._client.append_blob.create(**options) # type: ignore
1373
+ return cast(Dict[str, Union[str, datetime]], await self._client.append_blob.create(**options))
1168
1374
  except HttpResponseError as error:
1169
1375
  process_storage_error(error)
1170
1376
 
1171
1377
  @distributed_trace_async
1172
- async def create_snapshot(self, metadata=None, **kwargs):
1173
- # type: (Optional[Dict[str, str]], Any) -> Dict[str, Union[str, datetime]]
1378
+ async def create_snapshot(
1379
+ self, metadata: Optional[Dict[str, str]] = None,
1380
+ **kwargs: Any
1381
+ ) -> Dict[str, Union[str, datetime]]:
1174
1382
  """Creates a snapshot of the blob.
1175
1383
 
1176
1384
  A snapshot is a read-only version of a blob that's taken at a point in time.
@@ -1242,15 +1450,21 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1242
1450
  :dedent: 12
1243
1451
  :caption: Create a snapshot of the blob.
1244
1452
  """
1245
- options = self._create_snapshot_options(metadata=metadata, **kwargs)
1453
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
1454
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
1455
+ options = _create_snapshot_options(metadata=metadata, **kwargs)
1246
1456
  try:
1247
- return await self._client.blob.create_snapshot(**options) # type: ignore
1457
+ return cast(Dict[str, Any], await self._client.blob.create_snapshot(**options))
1248
1458
  except HttpResponseError as error:
1249
1459
  process_storage_error(error)
1250
1460
 
1251
1461
  @distributed_trace_async
1252
- async def start_copy_from_url(self, source_url, metadata=None, incremental_copy=False, **kwargs):
1253
- # type: (str, Optional[Dict[str, str]], bool, Any) -> Dict[str, Union[str, datetime]]
1462
+ async def start_copy_from_url(
1463
+ self, source_url: str,
1464
+ metadata: Optional[Dict[str, str]] = None,
1465
+ incremental_copy: bool = False,
1466
+ **kwargs: Any
1467
+ ) -> Dict[str, Union[str, datetime]]:
1254
1468
  """Copies a blob from the given URL.
1255
1469
 
1256
1470
  This operation returns a dictionary containing `copy_status` and `copy_id`,
@@ -1433,21 +1647,23 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1433
1647
  :dedent: 16
1434
1648
  :caption: Copy a blob from a URL.
1435
1649
  """
1436
- options = self._start_copy_from_url_options(
1437
- source_url=self._encode_source_url(source_url),
1650
+ options = _start_copy_from_url_options(
1651
+ source_url=source_url,
1438
1652
  metadata=metadata,
1439
1653
  incremental_copy=incremental_copy,
1440
1654
  **kwargs)
1441
1655
  try:
1442
1656
  if incremental_copy:
1443
- return await self._client.page_blob.copy_incremental(**options)
1444
- return await self._client.blob.start_copy_from_url(**options)
1657
+ return cast(Dict[str, Union[str, datetime]], await self._client.page_blob.copy_incremental(**options))
1658
+ return cast(Dict[str, Union[str, datetime]], await self._client.blob.start_copy_from_url(**options))
1445
1659
  except HttpResponseError as error:
1446
1660
  process_storage_error(error)
1447
1661
 
1448
1662
  @distributed_trace_async
1449
- async def abort_copy(self, copy_id, **kwargs):
1450
- # type: (Union[str, Dict[str, Any], BlobProperties], Any) -> None
1663
+ async def abort_copy(
1664
+ self, copy_id: Union[str, Dict[str, Any], BlobProperties],
1665
+ **kwargs: Any
1666
+ ) -> None:
1451
1667
  """Abort an ongoing copy operation.
1452
1668
 
1453
1669
  This will leave a destination blob with zero length and full metadata.
@@ -1468,15 +1684,18 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1468
1684
  :dedent: 16
1469
1685
  :caption: Abort copying a blob from URL.
1470
1686
  """
1471
- options = self._abort_copy_options(copy_id, **kwargs)
1687
+ options = _abort_copy_options(copy_id, **kwargs)
1472
1688
  try:
1473
1689
  await self._client.blob.abort_copy_from_url(**options)
1474
1690
  except HttpResponseError as error:
1475
1691
  process_storage_error(error)
1476
1692
 
1477
1693
  @distributed_trace_async
1478
- async def acquire_lease(self, lease_duration=-1, lease_id=None, **kwargs):
1479
- # type: (int, Optional[str], Any) -> BlobLeaseClient
1694
+ async def acquire_lease(
1695
+ self, lease_duration: int =-1,
1696
+ lease_id: Optional[str] = None,
1697
+ **kwargs: Any
1698
+ ) -> BlobLeaseClient:
1480
1699
  """Requests a new lease.
1481
1700
 
1482
1701
  If the blob does not have an active lease, the Blob
@@ -1532,13 +1751,12 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1532
1751
  :dedent: 12
1533
1752
  :caption: Acquiring a lease on a blob.
1534
1753
  """
1535
- lease = BlobLeaseClient(self, lease_id=lease_id) # type: ignore
1754
+ lease = BlobLeaseClient(self, lease_id=lease_id)
1536
1755
  await lease.acquire(lease_duration=lease_duration, **kwargs)
1537
1756
  return lease
1538
1757
 
1539
1758
  @distributed_trace_async
1540
- async def set_standard_blob_tier(self, standard_blob_tier, **kwargs):
1541
- # type: (Union[str, StandardBlobTier], Any) -> None
1759
+ async def set_standard_blob_tier(self, standard_blob_tier: Union[str, "StandardBlobTier"], **kwargs: Any) -> None:
1542
1760
  """This operation sets the tier on a block blob.
1543
1761
 
1544
1762
  A block blob's tier determines Hot/Cool/Archive storage type.
@@ -1590,19 +1808,18 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1590
1808
 
1591
1809
  @distributed_trace_async
1592
1810
  async def stage_block(
1593
- self, block_id, # type: str
1594
- data, # type: Union[Iterable[AnyStr], IO[AnyStr]]
1595
- length=None, # type: Optional[int]
1596
- **kwargs
1597
- ):
1598
- # type: (...) -> Dict[str, Any]
1811
+ self, block_id: str,
1812
+ data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]],
1813
+ length: Optional[int] = None,
1814
+ **kwargs: Any
1815
+ ) -> Dict[str, Any]:
1599
1816
  """Creates a new block to be committed as part of a blob.
1600
1817
 
1601
1818
  :param str block_id: A string value that identifies the block.
1602
1819
  The string should be less than or equal to 64 bytes in size.
1603
1820
  For a given blob, the block_id must be the same size for each block.
1604
1821
  :param data: The blob data.
1605
- :type data: Union[Iterable[AnyStr], IO[AnyStr]]
1822
+ :type data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]]
1606
1823
  :param int length: Size of the block.
1607
1824
  :keyword bool validate_content:
1608
1825
  If true, calculates an MD5 hash for each chunk of the blob. The storage
@@ -1641,26 +1858,29 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1641
1858
  :returns: Blob property dict.
1642
1859
  :rtype: Dict[str, Any]
1643
1860
  """
1644
- options = self._stage_block_options(
1645
- block_id,
1646
- data,
1861
+ if self.require_encryption or (self.key_encryption_key is not None):
1862
+ raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
1863
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
1864
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
1865
+ options = _stage_block_options(
1866
+ block_id=block_id,
1867
+ data=data,
1647
1868
  length=length,
1648
1869
  **kwargs)
1649
1870
  try:
1650
- return await self._client.block_blob.stage_block(**options)
1871
+ return cast(Dict[str, Any], await self._client.block_blob.stage_block(**options))
1651
1872
  except HttpResponseError as error:
1652
1873
  process_storage_error(error)
1653
1874
 
1654
1875
  @distributed_trace_async
1655
1876
  async def stage_block_from_url(
1656
- self, block_id, # type: Union[str, int]
1657
- source_url, # type: str
1658
- source_offset=None, # type: Optional[int]
1659
- source_length=None, # type: Optional[int]
1660
- source_content_md5=None, # type: Optional[Union[bytes, bytearray]]
1661
- **kwargs
1662
- ):
1663
- # type: (...) -> Dict[str, Any]
1877
+ self, block_id: str,
1878
+ source_url: str,
1879
+ source_offset: Optional[int] = None,
1880
+ source_length: Optional[int] = None,
1881
+ source_content_md5: Optional[Union[bytes, bytearray]] = None,
1882
+ **kwargs: Any
1883
+ ) -> Dict[str, Any]:
1664
1884
  """Creates a new block to be committed as part of a blob where
1665
1885
  the contents are read from a URL.
1666
1886
 
@@ -1704,21 +1924,25 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1704
1924
  :returns: Blob property dict.
1705
1925
  :rtype: Dict[str, Any]
1706
1926
  """
1707
- options = self._stage_block_from_url_options(
1708
- block_id,
1709
- source_url=self._encode_source_url(source_url),
1927
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
1928
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
1929
+ options = _stage_block_from_url_options(
1930
+ block_id=block_id,
1931
+ source_url=source_url,
1710
1932
  source_offset=source_offset,
1711
1933
  source_length=source_length,
1712
1934
  source_content_md5=source_content_md5,
1713
1935
  **kwargs)
1714
1936
  try:
1715
- return await self._client.block_blob.stage_block_from_url(**options)
1937
+ return cast(Dict[str, Any], await self._client.block_blob.stage_block_from_url(**options))
1716
1938
  except HttpResponseError as error:
1717
1939
  process_storage_error(error)
1718
1940
 
1719
1941
  @distributed_trace_async
1720
- async def get_block_list(self, block_list_type="committed", **kwargs):
1721
- # type: (Optional[str], Any) -> Tuple[List[BlobBlock], List[BlobBlock]]
1942
+ async def get_block_list(
1943
+ self, block_list_type: str = "committed",
1944
+ **kwargs: Any
1945
+ ) -> Tuple[List[BlobBlock], List[BlobBlock]]:
1722
1946
  """The Get Block List operation retrieves the list of blocks that have
1723
1947
  been uploaded as part of a block blob.
1724
1948
 
@@ -1743,7 +1967,7 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1743
1967
  see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob
1744
1968
  #other-client--per-operation-configuration>`__.
1745
1969
  :returns: A tuple of two lists - committed and uncommitted blocks
1746
- :rtype: tuple(list(~azure.storage.blob.BlobBlock), list(~azure.storage.blob.BlobBlock))
1970
+ :rtype: Tuple[List[BlobBlock], List[BlobBlock]]
1747
1971
  """
1748
1972
  access_conditions = get_access_conditions(kwargs.pop('lease', None))
1749
1973
  mod_conditions = get_modify_conditions(kwargs)
@@ -1757,16 +1981,15 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1757
1981
  **kwargs)
1758
1982
  except HttpResponseError as error:
1759
1983
  process_storage_error(error)
1760
- return self._get_block_list_result(blocks)
1984
+ return _get_block_list_result(blocks)
1761
1985
 
1762
1986
  @distributed_trace_async
1763
- async def commit_block_list( # type: ignore
1764
- self, block_list, # type: List[BlobBlock]
1765
- content_settings=None, # type: Optional[ContentSettings]
1766
- metadata=None, # type: Optional[Dict[str, str]]
1767
- **kwargs
1768
- ):
1769
- # type: (...) -> Dict[str, Union[str, datetime]]
1987
+ async def commit_block_list(
1988
+ self, block_list: List[BlobBlock],
1989
+ content_settings: Optional["ContentSettings"] = None,
1990
+ metadata: Optional[Dict[str, str]] = None,
1991
+ **kwargs: Any
1992
+ ) -> Dict[str, Union[str, datetime]]:
1770
1993
  """The Commit Block List operation writes a blob by specifying the list of
1771
1994
  block IDs that make up the blob.
1772
1995
 
@@ -1859,19 +2082,22 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1859
2082
  :returns: Blob-updated property dict (Etag and last modified).
1860
2083
  :rtype: dict(str, Any)
1861
2084
  """
1862
- options = self._commit_block_list_options(
1863
- block_list,
2085
+ if self.require_encryption or (self.key_encryption_key is not None):
2086
+ raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
2087
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
2088
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
2089
+ options = _commit_block_list_options(
2090
+ block_list=block_list,
1864
2091
  content_settings=content_settings,
1865
2092
  metadata=metadata,
1866
2093
  **kwargs)
1867
2094
  try:
1868
- return await self._client.block_blob.commit_block_list(**options) # type: ignore
2095
+ return cast(Dict[str, Any], await self._client.block_blob.commit_block_list(**options))
1869
2096
  except HttpResponseError as error:
1870
2097
  process_storage_error(error)
1871
2098
 
1872
2099
  @distributed_trace_async
1873
- async def set_premium_page_blob_tier(self, premium_page_blob_tier, **kwargs):
1874
- # type: (Union[str, PremiumPageBlobTier], **Any) -> None
2100
+ async def set_premium_page_blob_tier(self, premium_page_blob_tier: "PremiumPageBlobTier", **kwargs: Any) -> None:
1875
2101
  """Sets the page blob tiers on the blob. This API is only supported for page blobs on premium accounts.
1876
2102
 
1877
2103
  :param premium_page_blob_tier:
@@ -1912,8 +2138,7 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1912
2138
  process_storage_error(error)
1913
2139
 
1914
2140
  @distributed_trace_async
1915
- async def set_blob_tags(self, tags=None, **kwargs):
1916
- # type: (Optional[Dict[str, str]], **Any) -> Dict[str, Any]
2141
+ async def set_blob_tags(self, tags: Optional[Dict[str, str]] = None, **kwargs: Any) -> Dict[str, Any]:
1917
2142
  """The Set Tags operation enables users to set tags on a blob or specific blob version, but not snapshot.
1918
2143
  Each call to this operation replaces all existing tags attached to the blob. To remove all
1919
2144
  tags from the blob, call this operation with no tags set.
@@ -1954,15 +2179,15 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1954
2179
  :returns: Blob-updated property dict (Etag and last modified)
1955
2180
  :rtype: Dict[str, Any]
1956
2181
  """
1957
- options = self._set_blob_tags_options(tags=tags, **kwargs)
2182
+ version_id = get_version_id(self.version_id, kwargs)
2183
+ options = _set_blob_tags_options(version_id=version_id, tags=tags, **kwargs)
1958
2184
  try:
1959
- return await self._client.blob.set_tags(**options)
2185
+ return cast(Dict[str, Any], await self._client.blob.set_tags(**options))
1960
2186
  except HttpResponseError as error:
1961
2187
  process_storage_error(error)
1962
2188
 
1963
2189
  @distributed_trace_async
1964
- async def get_blob_tags(self, **kwargs):
1965
- # type: (**Any) -> Dict[str, str]
2190
+ async def get_blob_tags(self, **kwargs: Any) -> Dict[str, str]:
1966
2191
  """The Get Tags operation enables users to get tags on a blob or specific blob version, but not snapshot.
1967
2192
 
1968
2193
  .. versionadded:: 12.4.0
@@ -1987,21 +2212,21 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
1987
2212
  :returns: Key value pairs of blob tags.
1988
2213
  :rtype: Dict[str, str]
1989
2214
  """
1990
- options = self._get_blob_tags_options(**kwargs)
2215
+ version_id = get_version_id(self.version_id, kwargs)
2216
+ options = _get_blob_tags_options(version_id=version_id, snapshot=self.snapshot, **kwargs)
1991
2217
  try:
1992
2218
  _, tags = await self._client.blob.get_tags(**options)
1993
- return parse_tags(tags) # pylint: disable=protected-access
2219
+ return cast(Dict[str, str], parse_tags(tags)) # pylint: disable=protected-access
1994
2220
  except HttpResponseError as error:
1995
2221
  process_storage_error(error)
1996
2222
 
1997
2223
  @distributed_trace_async
1998
- async def get_page_ranges( # type: ignore
1999
- self, offset=None, # type: Optional[int]
2000
- length=None, # type: Optional[int]
2001
- previous_snapshot_diff=None, # type: Optional[Union[str, Dict[str, Any]]]
2002
- **kwargs
2003
- ):
2004
- # type: (...) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]
2224
+ async def get_page_ranges(
2225
+ self, offset: Optional[int] = None,
2226
+ length: Optional[int] = None,
2227
+ previous_snapshot_diff: Optional[Union[str, Dict[str, Any]]] = None,
2228
+ **kwargs: Any
2229
+ ) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]:
2005
2230
  """DEPRECATED: Returns the list of valid page ranges for a Page Blob or snapshot
2006
2231
  of a page blob.
2007
2232
 
@@ -2066,7 +2291,8 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2066
2291
  DeprecationWarning
2067
2292
  )
2068
2293
 
2069
- options = self._get_page_ranges_options(
2294
+ options = _get_page_ranges_options(
2295
+ snapshot=self.snapshot,
2070
2296
  offset=offset,
2071
2297
  length=length,
2072
2298
  previous_snapshot_diff=previous_snapshot_diff,
@@ -2082,13 +2308,13 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2082
2308
 
2083
2309
  @distributed_trace
2084
2310
  def list_page_ranges(
2085
- self,
2086
- *,
2087
- offset: Optional[int] = None,
2088
- length: Optional[int] = None,
2089
- previous_snapshot: Optional[Union[str, Dict[str, Any]]] = None,
2090
- **kwargs: Any
2091
- ) -> AsyncItemPaged[PageRange]:
2311
+ self,
2312
+ *,
2313
+ offset: Optional[int] = None,
2314
+ length: Optional[int] = None,
2315
+ previous_snapshot: Optional[Union[str, Dict[str, Any]]] = None,
2316
+ **kwargs: Any
2317
+ ) -> AsyncItemPaged[PageRange]:
2092
2318
  """Returns the list of valid page ranges for a Page Blob or snapshot
2093
2319
  of a page blob. If `previous_snapshot` is specified, the result will be
2094
2320
  a diff of changes between the target blob and the previous snapshot.
@@ -2152,7 +2378,8 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2152
2378
  :rtype: ~azure.core.paging.ItemPaged[~azure.storage.blob.PageRange]
2153
2379
  """
2154
2380
  results_per_page = kwargs.pop('results_per_page', None)
2155
- options = self._get_page_ranges_options(
2381
+ options = _get_page_ranges_options(
2382
+ snapshot=self.snapshot,
2156
2383
  offset=offset,
2157
2384
  length=length,
2158
2385
  previous_snapshot_diff=previous_snapshot,
@@ -2172,12 +2399,11 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2172
2399
 
2173
2400
  @distributed_trace_async
2174
2401
  async def get_page_range_diff_for_managed_disk(
2175
- self, previous_snapshot_url, # type: str
2176
- offset=None, # type: Optional[int]
2177
- length=None, # type: Optional[int]
2178
- **kwargs
2179
- ):
2180
- # type: (...) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]
2402
+ self, previous_snapshot_url: str,
2403
+ offset: Optional[int] = None,
2404
+ length: Optional[int] = None,
2405
+ **kwargs: Any
2406
+ ) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]:
2181
2407
  """Returns the list of valid page ranges for a managed disk or snapshot.
2182
2408
 
2183
2409
  .. note::
@@ -2236,7 +2462,8 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2236
2462
  The first element are filled page ranges, the 2nd element is cleared page ranges.
2237
2463
  :rtype: tuple(list(dict(str, str), list(dict(str, str))
2238
2464
  """
2239
- options = self._get_page_ranges_options(
2465
+ options = _get_page_ranges_options(
2466
+ snapshot=self.snapshot,
2240
2467
  offset=offset,
2241
2468
  length=length,
2242
2469
  prev_snapshot_url=previous_snapshot_url,
@@ -2248,12 +2475,11 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2248
2475
  return get_page_ranges_result(ranges)
2249
2476
 
2250
2477
  @distributed_trace_async
2251
- async def set_sequence_number( # type: ignore
2252
- self, sequence_number_action, # type: Union[str, SequenceNumberAction]
2253
- sequence_number=None, # type: Optional[str]
2254
- **kwargs
2255
- ):
2256
- # type: (...) -> Dict[str, Union[str, datetime]]
2478
+ async def set_sequence_number(
2479
+ self, sequence_number_action: Union[str, "SequenceNumberAction"],
2480
+ sequence_number: Optional[str] = None,
2481
+ **kwargs: Any
2482
+ ) -> Dict[str, Union[str, datetime]]:
2257
2483
  """Sets the blob sequence number.
2258
2484
 
2259
2485
  :param str sequence_number_action:
@@ -2299,16 +2525,14 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2299
2525
  :returns: Blob-updated property dict (Etag and last modified).
2300
2526
  :rtype: dict(str, Any)
2301
2527
  """
2302
- options = self._set_sequence_number_options(
2303
- sequence_number_action, sequence_number=sequence_number, **kwargs)
2528
+ options = _set_sequence_number_options(sequence_number_action, sequence_number=sequence_number, **kwargs)
2304
2529
  try:
2305
- return await self._client.page_blob.update_sequence_number(**options) # type: ignore
2530
+ return cast(Dict[str, Any], await self._client.page_blob.update_sequence_number(**options))
2306
2531
  except HttpResponseError as error:
2307
2532
  process_storage_error(error)
2308
2533
 
2309
2534
  @distributed_trace_async
2310
- async def resize_blob(self, size, **kwargs):
2311
- # type: (int, Any) -> Dict[str, Union[str, datetime]]
2535
+ async def resize_blob(self, size: int, **kwargs: Any) -> Dict[str, Union[str, datetime]]:
2312
2536
  """Resizes a page blob to the specified size.
2313
2537
 
2314
2538
  If the specified value is less than the current size of the blob,
@@ -2357,20 +2581,21 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2357
2581
  :returns: Blob-updated property dict (Etag and last modified).
2358
2582
  :rtype: dict(str, Any)
2359
2583
  """
2360
- options = self._resize_blob_options(size, **kwargs)
2584
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
2585
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
2586
+ options = _resize_blob_options(size=size, **kwargs)
2361
2587
  try:
2362
- return await self._client.page_blob.resize(**options) # type: ignore
2588
+ return cast(Dict[str, Any], await self._client.page_blob.resize(**options))
2363
2589
  except HttpResponseError as error:
2364
2590
  process_storage_error(error)
2365
2591
 
2366
2592
  @distributed_trace_async
2367
- async def upload_page( # type: ignore
2368
- self, page, # type: bytes
2369
- offset, # type: int
2370
- length, # type: int
2371
- **kwargs
2372
- ):
2373
- # type: (...) -> Dict[str, Union[str, datetime]]
2593
+ async def upload_page(
2594
+ self, page: bytes,
2595
+ offset: int,
2596
+ length: int,
2597
+ **kwargs: Any
2598
+ ) -> Dict[str, Union[str, datetime]]:
2374
2599
  """The Upload Pages operation writes a range of pages to a page blob.
2375
2600
 
2376
2601
  :param bytes page:
@@ -2452,24 +2677,28 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2452
2677
  :returns: Blob-updated property dict (Etag and last modified).
2453
2678
  :rtype: dict(str, Any)
2454
2679
  """
2455
- options = self._upload_page_options(
2680
+ if self.require_encryption or (self.key_encryption_key is not None):
2681
+ raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
2682
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
2683
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
2684
+ options = _upload_page_options(
2456
2685
  page=page,
2457
2686
  offset=offset,
2458
2687
  length=length,
2459
2688
  **kwargs)
2460
2689
  try:
2461
- return await self._client.page_blob.upload_pages(**options) # type: ignore
2690
+ return cast(Dict[str, Any], await self._client.page_blob.upload_pages(**options))
2462
2691
  except HttpResponseError as error:
2463
2692
  process_storage_error(error)
2464
2693
 
2465
2694
  @distributed_trace_async
2466
- async def upload_pages_from_url(self, source_url, # type: str
2467
- offset, # type: int
2468
- length, # type: int
2469
- source_offset, # type: int
2470
- **kwargs
2471
- ):
2472
- # type: (...) -> Dict[str, Any]
2695
+ async def upload_pages_from_url(
2696
+ self, source_url: str,
2697
+ offset: int,
2698
+ length: int,
2699
+ source_offset: int,
2700
+ **kwargs: Any
2701
+ ) -> Dict[str, Any]:
2473
2702
  """
2474
2703
  The Upload Pages operation writes a range of pages to a page blob where
2475
2704
  the contents are read from a URL.
@@ -2571,21 +2800,24 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2571
2800
  :rtype: Dict[str, Any]
2572
2801
  """
2573
2802
 
2574
- options = self._upload_pages_from_url_options(
2575
- source_url=self._encode_source_url(source_url),
2803
+ if self.require_encryption or (self.key_encryption_key is not None):
2804
+ raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
2805
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
2806
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
2807
+ options = _upload_pages_from_url_options(
2808
+ source_url=source_url,
2576
2809
  offset=offset,
2577
2810
  length=length,
2578
2811
  source_offset=source_offset,
2579
2812
  **kwargs
2580
2813
  )
2581
2814
  try:
2582
- return await self._client.page_blob.upload_pages_from_url(**options) # type: ignore
2815
+ return cast(Dict[str, Any], await self._client.page_blob.upload_pages_from_url(**options))
2583
2816
  except HttpResponseError as error:
2584
2817
  process_storage_error(error)
2585
2818
 
2586
2819
  @distributed_trace_async
2587
- async def clear_page(self, offset, length, **kwargs):
2588
- # type: (int, int, Any) -> Dict[str, Union[str, datetime]]
2820
+ async def clear_page(self, offset: int, length: int, **kwargs: Any) -> Dict[str, Union[str, datetime]]:
2589
2821
  """Clears a range of pages.
2590
2822
 
2591
2823
  :param int offset:
@@ -2648,19 +2880,26 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2648
2880
  :returns: Blob-updated property dict (Etag and last modified).
2649
2881
  :rtype: dict(str, Any)
2650
2882
  """
2651
- options = self._clear_page_options(offset, length, **kwargs)
2883
+ if self.require_encryption or (self.key_encryption_key is not None):
2884
+ raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
2885
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
2886
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
2887
+ options = _clear_page_options(
2888
+ offset=offset,
2889
+ length=length,
2890
+ **kwargs
2891
+ )
2652
2892
  try:
2653
- return await self._client.page_blob.clear_pages(**options) # type: ignore
2893
+ return cast(Dict[str, Any], await self._client.page_blob.clear_pages(**options))
2654
2894
  except HttpResponseError as error:
2655
2895
  process_storage_error(error)
2656
2896
 
2657
2897
  @distributed_trace_async
2658
- async def append_block( # type: ignore
2659
- self, data, # type: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]]
2660
- length=None, # type: Optional[int]
2661
- **kwargs
2662
- ):
2663
- # type: (...) -> Dict[str, Union[str, datetime, int]]
2898
+ async def append_block(
2899
+ self, data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]],
2900
+ length: Optional[int] = None,
2901
+ **kwargs: Any
2902
+ ) -> Dict[str, Union[str, datetime, int]]:
2664
2903
  """Commits a new block of data to the end of the existing append blob.
2665
2904
 
2666
2905
  :param data:
@@ -2738,22 +2977,27 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2738
2977
  :returns: Blob-updated property dict (Etag, last modified, append offset, committed block count).
2739
2978
  :rtype: dict(str, Any)
2740
2979
  """
2741
- options = self._append_block_options(
2742
- data,
2980
+ if self.require_encryption or (self.key_encryption_key is not None):
2981
+ raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
2982
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
2983
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
2984
+ options = _append_block_options(
2985
+ data=data,
2743
2986
  length=length,
2744
2987
  **kwargs
2745
2988
  )
2746
2989
  try:
2747
- return await self._client.append_blob.append_block(**options) # type: ignore
2990
+ return cast(Dict[str, Any], await self._client.append_blob.append_block(**options))
2748
2991
  except HttpResponseError as error:
2749
2992
  process_storage_error(error)
2750
2993
 
2751
2994
  @distributed_trace_async
2752
- async def append_block_from_url(self, copy_source_url, # type: str
2753
- source_offset=None, # type: Optional[int]
2754
- source_length=None, # type: Optional[int]
2755
- **kwargs):
2756
- # type: (...) -> Dict[str, Union[str, datetime, int]]
2995
+ async def append_block_from_url(
2996
+ self, copy_source_url: str,
2997
+ source_offset: Optional[int] = None,
2998
+ source_length: Optional[int] = None,
2999
+ **kwargs: Any
3000
+ ) -> Dict[str, Union[str, datetime, int]]:
2757
3001
  """
2758
3002
  Creates a new block to be committed as part of a blob, where the contents are read from a source url.
2759
3003
 
@@ -2848,20 +3092,24 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2848
3092
  :returns: Result after appending a new block.
2849
3093
  :rtype: Dict[str, Union[str, datetime, int]]
2850
3094
  """
2851
- options = self._append_block_from_url_options(
2852
- copy_source_url=self._encode_source_url(copy_source_url),
3095
+ if self.require_encryption or (self.key_encryption_key is not None):
3096
+ raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
3097
+ if kwargs.get('cpk') and self.scheme.lower() != 'https':
3098
+ raise ValueError("Customer provided encryption key must be used over HTTPS.")
3099
+ options = _append_block_from_url_options(
3100
+ copy_source_url=copy_source_url,
2853
3101
  source_offset=source_offset,
2854
3102
  source_length=source_length,
2855
3103
  **kwargs
2856
3104
  )
2857
3105
  try:
2858
- return await self._client.append_blob.append_block_from_url(**options) # type: ignore
3106
+ return cast(Dict[str, Union[str, datetime, int]],
3107
+ await self._client.append_blob.append_block_from_url(**options))
2859
3108
  except HttpResponseError as error:
2860
3109
  process_storage_error(error)
2861
3110
 
2862
3111
  @distributed_trace_async
2863
- async def seal_append_blob(self, **kwargs):
2864
- # type: (...) -> Dict[str, Union[str, datetime, int]]
3112
+ async def seal_append_blob(self, **kwargs: Any) -> Dict[str, Union[str, datetime, int]]:
2865
3113
  """The Seal operation seals the Append Blob to make it read-only.
2866
3114
 
2867
3115
  .. versionadded:: 12.4.0
@@ -2902,14 +3150,15 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2902
3150
  :returns: Blob-updated property dict (Etag, last modified, append offset, committed block count).
2903
3151
  :rtype: dict(str, Any)
2904
3152
  """
2905
- options = self._seal_append_blob_options(**kwargs)
3153
+ if self.require_encryption or (self.key_encryption_key is not None):
3154
+ raise ValueError(_ERROR_UNSUPPORTED_METHOD_FOR_ENCRYPTION)
3155
+ options = _seal_append_blob_options(**kwargs)
2906
3156
  try:
2907
- return await self._client.append_blob.seal(**options) # type: ignore
3157
+ return cast(Dict[str, Any], await self._client.append_blob.seal(**options))
2908
3158
  except HttpResponseError as error:
2909
3159
  process_storage_error(error)
2910
3160
 
2911
- def _get_container_client(self): # pylint: disable=client-method-missing-kwargs
2912
- # type: (...) -> ContainerClient
3161
+ def _get_container_client(self) -> "ContainerClient":
2913
3162
  """Get a client to interact with the blob's parent container.
2914
3163
 
2915
3164
  The container need not already exist. Defaults to current blob's credentials.
@@ -2930,7 +3179,8 @@ class BlobClient(AsyncStorageAccountHostsMixin, BlobClientBase, StorageEncryptio
2930
3179
  if not isinstance(self._pipeline._transport, AsyncTransportWrapper): # pylint: disable = protected-access
2931
3180
  _pipeline = AsyncPipeline(
2932
3181
  transport=AsyncTransportWrapper(self._pipeline._transport), # pylint: disable = protected-access
2933
- policies=self._pipeline._impl_policies # pylint: disable = protected-access
3182
+ policies=cast(Iterable["AsyncHTTPPolicy"],
3183
+ self._pipeline._impl_policies) # pylint: disable = protected-access
2934
3184
  )
2935
3185
  else:
2936
3186
  _pipeline = self._pipeline # pylint: disable = protected-access