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
@@ -7,33 +7,30 @@
7
7
 
8
8
  import functools
9
9
  import warnings
10
+ from datetime import datetime
10
11
  from typing import (
11
- Any, AnyStr, Dict, List, IO, Iterable, Iterator, Optional, overload, Union,
12
+ Any, AnyStr, cast, Dict, List, IO, Iterable, Iterator, Optional, overload, Union,
12
13
  TYPE_CHECKING
13
14
  )
14
- from urllib.parse import urlparse, quote, unquote
15
-
15
+ from urllib.parse import unquote, urlparse
16
16
  from typing_extensions import Self
17
17
 
18
- from azure.core import MatchConditions
19
18
  from azure.core.exceptions import HttpResponseError, ResourceNotFoundError
20
19
  from azure.core.paging import ItemPaged
21
20
  from azure.core.pipeline import Pipeline
22
- from azure.core.pipeline.transport import HttpRequest
23
21
  from azure.core.tracing.decorator import distributed_trace
24
- from ._shared.base_client import StorageAccountHostsMixin, TransportWrapper, parse_connection_str, parse_query
25
- from ._shared.request_handlers import add_metadata_headers, serialize_iso
26
- from ._shared.response_handlers import (
27
- process_storage_error,
28
- return_response_headers,
29
- return_headers_and_deserialized
30
- )
31
- from ._generated import AzureBlobStorage
32
- from ._generated.models import SignedIdentifier
33
22
  from ._blob_client import BlobClient
23
+ from ._container_client_helpers import (
24
+ _format_url,
25
+ _generate_delete_blobs_options,
26
+ _generate_set_tiers_options,
27
+ _parse_url
28
+ )
34
29
  from ._deserialize import deserialize_container_properties
35
30
  from ._download import StorageStreamDownloader
36
31
  from ._encryption import StorageEncryptionMixin
32
+ from ._generated import AzureBlobStorage
33
+ from ._generated.models import SignedIdentifier
37
34
  from ._lease import BlobLeaseClient
38
35
  from ._list_blobs_helper import (
39
36
  BlobNamesPaged,
@@ -43,36 +40,30 @@ from ._list_blobs_helper import (
43
40
  IgnoreListBlobsDeserializer
44
41
  )
45
42
  from ._models import (
46
- ContainerProperties,
47
43
  BlobProperties,
48
44
  BlobType,
45
+ ContainerProperties,
49
46
  FilteredBlob
50
47
  )
51
- from ._serialize import get_modify_conditions, get_container_cpk_scope_info, get_api_version, get_access_conditions
48
+ from ._serialize import get_access_conditions, get_api_version, get_container_cpk_scope_info, get_modify_conditions
49
+ from ._shared.base_client import parse_connection_str, StorageAccountHostsMixin, TransportWrapper
50
+ from ._shared.request_handlers import add_metadata_headers, serialize_iso
51
+ from ._shared.response_handlers import (
52
+ process_storage_error,
53
+ return_headers_and_deserialized,
54
+ return_response_headers
55
+ )
52
56
 
53
57
  if TYPE_CHECKING:
54
58
  from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential, TokenCredential
55
59
  from azure.core.pipeline.transport import HttpResponse # pylint: disable=C4756
56
- from datetime import datetime
57
- from ._models import ( # pylint: disable=unused-import
58
- PublicAccess,
60
+ from azure.storage.blob import BlobServiceClient
61
+ from ._models import (
59
62
  AccessPolicy,
60
- StandardBlobTier,
61
- PremiumPageBlobTier)
62
-
63
-
64
- def _get_blob_name(blob):
65
- """Return the blob name.
66
-
67
- :param blob: A blob string or BlobProperties
68
- :type blob: str or BlobProperties
69
- :returns: The name of the blob.
70
- :rtype: str
71
- """
72
- try:
73
- return blob.get('name')
74
- except AttributeError:
75
- return blob
63
+ PremiumPageBlobTier,
64
+ PublicAccess,
65
+ StandardBlobTier
66
+ )
76
67
 
77
68
 
78
69
  class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # pylint: disable=too-many-public-methods
@@ -143,23 +134,13 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
143
134
  :caption: Creating the container client directly.
144
135
  """
145
136
  def __init__(
146
- self, account_url: str,
147
- container_name: str,
148
- credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
149
- **kwargs: Any
150
- ) -> None:
151
- try:
152
- if not account_url.lower().startswith('http'):
153
- account_url = "https://" + account_url
154
- except AttributeError as exc:
155
- raise ValueError("Container URL must be a string.") from exc
156
- parsed_url = urlparse(account_url.rstrip('/'))
157
- if not container_name:
158
- raise ValueError("Please specify a container name.")
159
- if not parsed_url.netloc:
160
- raise ValueError(f"Invalid URL: {account_url}")
137
+ self, account_url: str,
138
+ container_name: str,
139
+ credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
140
+ **kwargs: Any
141
+ ) -> None:
142
+ parsed_url, sas_token = _parse_url(account_url=account_url, container_name=container_name)
161
143
 
162
- _, sas_token = parse_query(parsed_url.query)
163
144
  self.container_name = container_name
164
145
  # This parameter is used for the hierarchy traversal. Give precedence to credential.
165
146
  self._raw_credential = credential if credential else sas_token
@@ -169,23 +150,25 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
169
150
  self._client = self._build_generated_client()
170
151
  self._configure_encryption(kwargs)
171
152
 
172
- def _build_generated_client(self):
153
+ def _build_generated_client(self) -> AzureBlobStorage:
173
154
  client = AzureBlobStorage(self.url, base_url=self.url, pipeline=self._pipeline)
174
- client._config.version = self._api_version # pylint: disable=protected-access
155
+ client._config.version = self._api_version # type: ignore [assignment] # pylint: disable=protected-access
175
156
  return client
176
157
 
177
158
  def _format_url(self, hostname):
178
- container_name = self.container_name
179
- if isinstance(container_name, str):
180
- container_name = container_name.encode('UTF-8')
181
- return f"{self.scheme}://{hostname}/{quote(container_name)}{self._query_str}"
159
+ return _format_url(
160
+ container_name=self.container_name,
161
+ hostname=hostname,
162
+ scheme=self.scheme,
163
+ query_str=self._query_str
164
+ )
182
165
 
183
166
  @classmethod
184
167
  def from_container_url(
185
- cls, container_url: str,
186
- credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
187
- **kwargs: Any
188
- ) -> Self:
168
+ cls, container_url: str,
169
+ credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
170
+ **kwargs: Any
171
+ ) -> Self:
189
172
  """Create ContainerClient from a container url.
190
173
 
191
174
  :param str container_url:
@@ -234,11 +217,11 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
234
217
 
235
218
  @classmethod
236
219
  def from_connection_string(
237
- cls, conn_str: str,
238
- container_name: str,
239
- credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
240
- **kwargs: Any
241
- ) -> Self:
220
+ cls, conn_str: str,
221
+ container_name: str,
222
+ credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
223
+ **kwargs: Any
224
+ ) -> Self:
242
225
  """Create ContainerClient from a Connection String.
243
226
 
244
227
  :param str conn_str:
@@ -282,8 +265,11 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
282
265
  account_url, container_name=container_name, credential=credential, **kwargs)
283
266
 
284
267
  @distributed_trace
285
- def create_container(self, metadata=None, public_access=None, **kwargs):
286
- # type: (Optional[Dict[str, str]], Optional[Union[PublicAccess, str]], **Any) -> Dict[str, Union[str, datetime]]
268
+ def create_container(
269
+ self, metadata: Optional[Dict[str, str]] = None,
270
+ public_access: Optional[Union["PublicAccess", str]] = None,
271
+ **kwargs: Any
272
+ ) -> Dict[str, Union[str, "datetime"]]:
287
273
  """
288
274
  Creates a new container under the specified account. If the container
289
275
  with the same name already exists, the operation fails.
@@ -335,8 +321,7 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
335
321
  process_storage_error(error)
336
322
 
337
323
  @distributed_trace
338
- def _rename_container(self, new_name, **kwargs):
339
- # type: (str, **Any) -> ContainerClient
324
+ def _rename_container(self, new_name: str, **kwargs: Any) -> "ContainerClient":
340
325
  """Renames a container.
341
326
 
342
327
  Operation is successful only if the source container exists.
@@ -374,9 +359,7 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
374
359
  process_storage_error(error)
375
360
 
376
361
  @distributed_trace
377
- def delete_container(
378
- self, **kwargs):
379
- # type: (Any) -> None
362
+ def delete_container(self, **kwargs: Any) -> None:
380
363
  """
381
364
  Marks the specified container for deletion. The container and any blobs
382
365
  contained within it are later deleted during garbage collection.
@@ -435,10 +418,10 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
435
418
 
436
419
  @distributed_trace
437
420
  def acquire_lease(
438
- self, lease_duration=-1, # type: int
439
- lease_id=None, # type: Optional[str]
440
- **kwargs):
441
- # type: (...) -> BlobLeaseClient
421
+ self, lease_duration: int =-1,
422
+ lease_id: Optional[str] = None,
423
+ **kwargs: Any
424
+ ) -> BlobLeaseClient:
442
425
  """
443
426
  Requests a new lease. If the container does not have an active lease,
444
427
  the Blob service creates a lease on the container and returns a new
@@ -494,8 +477,7 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
494
477
  return lease
495
478
 
496
479
  @distributed_trace
497
- def get_account_information(self, **kwargs):
498
- # type: (**Any) -> Dict[str, str]
480
+ def get_account_information(self, **kwargs: Any) -> Dict[str, str]:
499
481
  """Gets information related to the storage account.
500
482
 
501
483
  The information can also be retrieved if the user has a SAS to a container or blob.
@@ -510,8 +492,7 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
510
492
  process_storage_error(error)
511
493
 
512
494
  @distributed_trace
513
- def get_container_properties(self, **kwargs):
514
- # type: (Any) -> ContainerProperties
495
+ def get_container_properties(self, **kwargs: Any) -> ContainerProperties:
515
496
  """Returns all user-defined metadata and system properties for the specified
516
497
  container. The data returned does not include the container's list of blobs.
517
498
 
@@ -552,8 +533,7 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
552
533
  return response # type: ignore
553
534
 
554
535
  @distributed_trace
555
- def exists(self, **kwargs):
556
- # type: (**Any) -> bool
536
+ def exists(self, **kwargs: Any) -> bool:
557
537
  """
558
538
  Returns True if a container exists and returns False otherwise.
559
539
 
@@ -576,11 +556,10 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
576
556
  return False
577
557
 
578
558
  @distributed_trace
579
- def set_container_metadata( # type: ignore
580
- self, metadata=None, # type: Optional[Dict[str, str]]
581
- **kwargs
582
- ):
583
- # type: (...) -> Dict[str, Union[str, datetime]]
559
+ def set_container_metadata(
560
+ self, metadata: Optional[Dict[str, str]] = None,
561
+ **kwargs: Any
562
+ ) -> Dict[str, Union[str, "datetime"]]:
584
563
  """Sets one or more user-defined name-value pairs for the specified
585
564
  container. Each call to this operation replaces all existing metadata
586
565
  attached to the container. To remove all metadata from the container,
@@ -645,8 +624,7 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
645
624
  process_storage_error(error)
646
625
 
647
626
  @distributed_trace
648
- def _get_blob_service_client(self): # pylint: disable=client-method-missing-kwargs
649
- # type: (...) -> BlobServiceClient
627
+ def _get_blob_service_client(self) -> "BlobServiceClient": # pylint: disable=client-method-missing-kwargs
650
628
  """Get a client to interact with the container's parent service account.
651
629
 
652
630
  Defaults to current container's credentials.
@@ -679,8 +657,7 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
679
657
  key_resolver_function=self.key_resolver_function, _pipeline=_pipeline)
680
658
 
681
659
  @distributed_trace
682
- def get_container_access_policy(self, **kwargs):
683
- # type: (Any) -> Dict[str, Any]
660
+ def get_container_access_policy(self, **kwargs: Any) -> Dict[str, Any]:
684
661
  """Gets the permissions for the specified container.
685
662
  The permissions indicate whether container data may be accessed publicly.
686
663
 
@@ -724,10 +701,10 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
724
701
 
725
702
  @distributed_trace
726
703
  def set_container_access_policy(
727
- self, signed_identifiers, # type: Dict[str, AccessPolicy]
728
- public_access=None, # type: Optional[Union[str, PublicAccess]]
729
- **kwargs
730
- ): # type: (...) -> Dict[str, Union[str, datetime]]
704
+ self, signed_identifiers: Dict[str, "AccessPolicy"],
705
+ public_access: Optional[Union[str, "PublicAccess"]] = None,
706
+ **kwargs: Any
707
+ ) -> Dict[str, Union[str, datetime]]:
731
708
  """Sets the permissions for the specified container or stored access
732
709
  policies that may be used with Shared Access Signatures. The permissions
733
710
  indicate whether blobs in a container may be accessed publicly.
@@ -789,14 +766,14 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
789
766
  access_conditions = get_access_conditions(lease)
790
767
  timeout = kwargs.pop('timeout', None)
791
768
  try:
792
- return self._client.container.set_access_policy(
769
+ return cast(Dict[str, Union[str, datetime]], self._client.container.set_access_policy(
793
770
  container_acl=signed_identifiers or None,
794
771
  timeout=timeout,
795
772
  access=public_access,
796
773
  lease_access_conditions=access_conditions,
797
774
  modified_access_conditions=mod_conditions,
798
775
  cls=return_response_headers,
799
- **kwargs)
776
+ **kwargs))
800
777
  except HttpResponseError as error:
801
778
  process_storage_error(error)
802
779
 
@@ -851,7 +828,7 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
851
828
  timeout=timeout,
852
829
  **kwargs)
853
830
  return ItemPaged(
854
- command, prefix=name_starts_with, results_per_page=results_per_page,
831
+ command, prefix=name_starts_with, results_per_page=results_per_page, container=self.container_name,
855
832
  page_iterator_class=BlobPropertiesPaged)
856
833
 
857
834
  @distributed_trace
@@ -897,6 +874,7 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
897
874
  command,
898
875
  prefix=name_starts_with,
899
876
  results_per_page=results_per_page,
877
+ container=self.container_name,
900
878
  page_iterator_class=BlobNamesPaged)
901
879
 
902
880
  @distributed_trace
@@ -905,7 +883,7 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
905
883
  include: Optional[Union[List[str], str]] = None,
906
884
  delimiter: str = "/",
907
885
  **kwargs: Any
908
- ) -> ItemPaged[BlobProperties]:
886
+ ) -> ItemPaged[BlobProperties]:
909
887
  """Returns a generator to list the blobs under the specified container.
910
888
  The generator will lazily follow the continuation tokens returned by
911
889
  the service. This operation will list blobs in accordance with a hierarchy,
@@ -952,14 +930,14 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
952
930
  command,
953
931
  prefix=name_starts_with,
954
932
  results_per_page=results_per_page,
933
+ container=self.container_name,
955
934
  delimiter=delimiter)
956
935
 
957
936
  @distributed_trace
958
937
  def find_blobs_by_tags(
959
- self, filter_expression, # type: str
960
- **kwargs # type: Optional[Any]
961
- ):
962
- # type: (...) -> ItemPaged[FilteredBlob]
938
+ self, filter_expression: str,
939
+ **kwargs: Any
940
+ ) -> ItemPaged[FilteredBlob]:
963
941
  """Returns a generator to list the blobs under the specified container whose tags
964
942
  match the given search expression.
965
943
  The generator will lazily follow the continuation tokens returned by
@@ -987,18 +965,18 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
987
965
  where=filter_expression,
988
966
  **kwargs)
989
967
  return ItemPaged(
990
- command, results_per_page=results_per_page,
968
+ command, results_per_page=results_per_page, container=self.container_name,
991
969
  page_iterator_class=FilteredBlobPaged)
992
970
 
993
971
  @distributed_trace
994
972
  def upload_blob(
995
- self, name: str,
996
- data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]],
997
- blob_type: Union[str, BlobType] = BlobType.BlockBlob,
998
- length: Optional[int] = None,
999
- metadata: Optional[Dict[str, str]] = None,
1000
- **kwargs
1001
- ) -> BlobClient:
973
+ self, name: str,
974
+ data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]],
975
+ blob_type: Union[str, BlobType] = BlobType.BLOCKBLOB,
976
+ length: Optional[int] = None,
977
+ metadata: Optional[Dict[str, str]] = None,
978
+ **kwargs
979
+ ) -> BlobClient:
1002
980
  """Creates a new blob from a data source with automatic chunking.
1003
981
 
1004
982
  :param str name: The blob with which to interact.
@@ -1135,11 +1113,10 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
1135
1113
 
1136
1114
  @distributed_trace
1137
1115
  def delete_blob(
1138
- self, blob: str,
1139
- delete_snapshots: Optional[str] = None,
1140
- **kwargs: Any
1141
- ):
1142
- # type: (...) -> None
1116
+ self, blob: str,
1117
+ delete_snapshots: Optional[str] = None,
1118
+ **kwargs: Any
1119
+ ) -> None:
1143
1120
  """Marks the specified blob or snapshot for deletion.
1144
1121
 
1145
1122
  The blob is later deleted during garbage collection.
@@ -1217,35 +1194,35 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
1217
1194
 
1218
1195
  @overload
1219
1196
  def download_blob(
1220
- self, blob: str,
1221
- offset: int = None,
1222
- length: int = None,
1223
- *,
1224
- encoding: str,
1225
- **kwargs: Any
1197
+ self, blob: str,
1198
+ offset: Optional[int] = None,
1199
+ length: Optional[int] = None,
1200
+ *,
1201
+ encoding: str,
1202
+ **kwargs: Any
1226
1203
  ) -> StorageStreamDownloader[str]:
1227
1204
  ...
1228
1205
 
1229
1206
  @overload
1230
1207
  def download_blob(
1231
- self, blob: str,
1232
- offset: int = None,
1233
- length: int = None,
1234
- *,
1235
- encoding: None = None,
1236
- **kwargs: Any
1208
+ self, blob: str,
1209
+ offset: Optional[int] = None,
1210
+ length: Optional[int] = None,
1211
+ *,
1212
+ encoding: None = None,
1213
+ **kwargs: Any
1237
1214
  ) -> StorageStreamDownloader[bytes]:
1238
1215
  ...
1239
1216
 
1240
1217
  @distributed_trace
1241
1218
  def download_blob(
1242
- self, blob: str,
1243
- offset: int = None,
1244
- length: int = None,
1245
- *,
1246
- encoding: Optional[str] = None,
1247
- **kwargs: Any
1248
- ) -> StorageStreamDownloader:
1219
+ self, blob: str,
1220
+ offset: Optional[int] = None,
1221
+ length: Optional[int] = None,
1222
+ *,
1223
+ encoding: Union[str, None] = None,
1224
+ **kwargs: Any
1225
+ ) -> Union[StorageStreamDownloader[str], StorageStreamDownloader[bytes]]:
1249
1226
  """Downloads a blob to the StorageStreamDownloader. The readall() method must
1250
1227
  be used to read all the content or readinto() must be used to download the blob into
1251
1228
  a stream. Using chunks() returns an iterator which allows the user to iterate over the content in chunks.
@@ -1342,131 +1319,11 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
1342
1319
  encoding=encoding,
1343
1320
  **kwargs)
1344
1321
 
1345
- # This code is a copy from _generated.
1346
- # Once Autorest is able to provide request preparation this code should be removed.
1347
- def _generate_delete_blobs_subrequest_options(
1348
- self, snapshot=None,
1349
- version_id=None,
1350
- delete_snapshots=None,
1351
- lease_access_conditions=None,
1352
- modified_access_conditions=None,
1353
- **kwargs
1354
- ):
1355
- lease_id = None
1356
- if lease_access_conditions is not None:
1357
- lease_id = lease_access_conditions.lease_id
1358
- if_modified_since = None
1359
- if modified_access_conditions is not None:
1360
- if_modified_since = modified_access_conditions.if_modified_since
1361
- if_unmodified_since = None
1362
- if modified_access_conditions is not None:
1363
- if_unmodified_since = modified_access_conditions.if_unmodified_since
1364
- if_match = None
1365
- if modified_access_conditions is not None:
1366
- if_match = modified_access_conditions.if_match
1367
- if_none_match = None
1368
- if modified_access_conditions is not None:
1369
- if_none_match = modified_access_conditions.if_none_match
1370
- if_tags = None
1371
- if modified_access_conditions is not None:
1372
- if_tags = modified_access_conditions.if_tags
1373
-
1374
- # Construct parameters
1375
- timeout = kwargs.pop('timeout', None)
1376
- query_parameters = {}
1377
- if snapshot is not None:
1378
- query_parameters['snapshot'] = self._client._serialize.query("snapshot", snapshot, 'str') # pylint: disable=protected-access
1379
- if version_id is not None:
1380
- query_parameters['versionid'] = self._client._serialize.query("version_id", version_id, 'str') # pylint: disable=protected-access
1381
- if timeout is not None:
1382
- query_parameters['timeout'] = self._client._serialize.query("timeout", timeout, 'int', minimum=0) # pylint: disable=protected-access
1383
-
1384
- # Construct headers
1385
- header_parameters = {}
1386
- if delete_snapshots is not None:
1387
- header_parameters['x-ms-delete-snapshots'] = self._client._serialize.header( # pylint: disable=protected-access
1388
- "delete_snapshots", delete_snapshots, 'DeleteSnapshotsOptionType')
1389
- if lease_id is not None:
1390
- header_parameters['x-ms-lease-id'] = self._client._serialize.header( # pylint: disable=protected-access
1391
- "lease_id", lease_id, 'str')
1392
- if if_modified_since is not None:
1393
- header_parameters['If-Modified-Since'] = self._client._serialize.header( # pylint: disable=protected-access
1394
- "if_modified_since", if_modified_since, 'rfc-1123')
1395
- if if_unmodified_since is not None:
1396
- header_parameters['If-Unmodified-Since'] = self._client._serialize.header( # pylint: disable=protected-access
1397
- "if_unmodified_since", if_unmodified_since, 'rfc-1123')
1398
- if if_match is not None:
1399
- header_parameters['If-Match'] = self._client._serialize.header( # pylint: disable=protected-access
1400
- "if_match", if_match, 'str')
1401
- if if_none_match is not None:
1402
- header_parameters['If-None-Match'] = self._client._serialize.header( # pylint: disable=protected-access
1403
- "if_none_match", if_none_match, 'str')
1404
- if if_tags is not None:
1405
- header_parameters['x-ms-if-tags'] = self._client._serialize.header("if_tags", if_tags, 'str') # pylint: disable=protected-access
1406
-
1407
- return query_parameters, header_parameters
1408
-
1409
- def _generate_delete_blobs_options(
1410
- self, *blobs: Union[str, Dict[str, Any], BlobProperties],
1411
- **kwargs: Any
1412
- ):
1413
- timeout = kwargs.pop('timeout', None)
1414
- raise_on_any_failure = kwargs.pop('raise_on_any_failure', True)
1415
- delete_snapshots = kwargs.pop('delete_snapshots', None)
1416
- if_modified_since = kwargs.pop('if_modified_since', None)
1417
- if_unmodified_since = kwargs.pop('if_unmodified_since', None)
1418
- if_tags_match_condition = kwargs.pop('if_tags_match_condition', None)
1419
- kwargs.update({'raise_on_any_failure': raise_on_any_failure,
1420
- 'sas': self._query_str.replace('?', '&'),
1421
- 'timeout': '&timeout=' + str(timeout) if timeout else "",
1422
- 'path': self.container_name,
1423
- 'restype': 'restype=container&'
1424
- })
1425
-
1426
- reqs = []
1427
- for blob in blobs:
1428
- blob_name = _get_blob_name(blob)
1429
- container_name = self.container_name
1430
-
1431
- try:
1432
- options = BlobClient._generic_delete_blob_options( # pylint: disable=protected-access
1433
- snapshot=blob.get('snapshot'),
1434
- version_id=blob.get('version_id'),
1435
- delete_snapshots=delete_snapshots or blob.get('delete_snapshots'),
1436
- lease=blob.get('lease_id'),
1437
- if_modified_since=if_modified_since or blob.get('if_modified_since'),
1438
- if_unmodified_since=if_unmodified_since or blob.get('if_unmodified_since'),
1439
- etag=blob.get('etag'),
1440
- if_tags_match_condition=if_tags_match_condition or blob.get('if_tags_match_condition'),
1441
- match_condition=blob.get('match_condition') or MatchConditions.IfNotModified if blob.get('etag')
1442
- else None,
1443
- timeout=blob.get('timeout'),
1444
- )
1445
- except AttributeError:
1446
- options = BlobClient._generic_delete_blob_options( # pylint: disable=protected-access
1447
- delete_snapshots=delete_snapshots,
1448
- if_modified_since=if_modified_since,
1449
- if_unmodified_since=if_unmodified_since,
1450
- if_tags_match_condition=if_tags_match_condition
1451
- )
1452
-
1453
- query_parameters, header_parameters = self._generate_delete_blobs_subrequest_options(**options)
1454
-
1455
- req = HttpRequest(
1456
- "DELETE",
1457
- f"/{quote(container_name)}/{quote(blob_name, safe='/~')}{self._query_str}",
1458
- headers=header_parameters
1459
- )
1460
- req.format_parameters(query_parameters)
1461
- reqs.append(req)
1462
-
1463
- return reqs, kwargs
1464
-
1465
1322
  @distributed_trace
1466
1323
  def delete_blobs( # pylint: disable=delete-operation-wrong-return-type
1467
- self, *blobs: Union[str, Dict[str, Any], BlobProperties],
1468
- **kwargs: Any
1469
- ) -> Iterator["HttpResponse"]:
1324
+ self, *blobs: Union[str, Dict[str, Any], BlobProperties],
1325
+ **kwargs: Any
1326
+ ) -> Iterator["HttpResponse"]:
1470
1327
  """Marks the specified blobs or snapshots for deletion.
1471
1328
 
1472
1329
  The blobs are later deleted during garbage collection.
@@ -1509,7 +1366,7 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
1509
1366
  timeout for subrequest:
1510
1367
  key: 'timeout', value type: int
1511
1368
 
1512
- :type blobs: str or dict(str, Any) or ~azure.storage.blob.BlobProperties
1369
+ :type blobs: Union[str, Dict[str, Any], BlobProperties]
1513
1370
  :keyword str delete_snapshots:
1514
1371
  Required if a blob has associated snapshots. Values include:
1515
1372
  - "only": Deletes only the blobs snapshots.
@@ -1556,99 +1413,19 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
1556
1413
  if len(blobs) == 0:
1557
1414
  return iter([])
1558
1415
 
1559
- reqs, options = self._generate_delete_blobs_options(*blobs, **kwargs)
1416
+ reqs, options = _generate_delete_blobs_options(
1417
+ self._query_str,
1418
+ self.container_name,
1419
+ self._client,
1420
+ *blobs,
1421
+ **kwargs
1422
+ )
1560
1423
 
1561
1424
  return self._batch_send(*reqs, **options)
1562
1425
 
1563
- # This code is a copy from _generated.
1564
- # Once Autorest is able to provide request preparation this code should be removed.
1565
- def _generate_set_tiers_subrequest_options(
1566
- self, tier, snapshot=None, version_id=None, rehydrate_priority=None, lease_access_conditions=None, **kwargs
1567
- ):
1568
- if not tier:
1569
- raise ValueError("A blob tier must be specified")
1570
- if snapshot and version_id:
1571
- raise ValueError("Snapshot and version_id cannot be set at the same time")
1572
- if_tags = kwargs.pop('if_tags', None)
1573
-
1574
- lease_id = None
1575
- if lease_access_conditions is not None:
1576
- lease_id = lease_access_conditions.lease_id
1577
-
1578
- comp = "tier"
1579
- timeout = kwargs.pop('timeout', None)
1580
- # Construct parameters
1581
- query_parameters = {}
1582
- if snapshot is not None:
1583
- query_parameters['snapshot'] = self._client._serialize.query("snapshot", snapshot, 'str') # pylint: disable=protected-access
1584
- if version_id is not None:
1585
- query_parameters['versionid'] = self._client._serialize.query("version_id", version_id, 'str') # pylint: disable=protected-access
1586
- if timeout is not None:
1587
- query_parameters['timeout'] = self._client._serialize.query("timeout", timeout, 'int', minimum=0) # pylint: disable=protected-access
1588
- query_parameters['comp'] = self._client._serialize.query("comp", comp, 'str') # pylint: disable=protected-access, specify-parameter-names-in-call
1589
-
1590
- # Construct headers
1591
- header_parameters = {}
1592
- header_parameters['x-ms-access-tier'] = self._client._serialize.header("tier", tier, 'str') # pylint: disable=protected-access, specify-parameter-names-in-call
1593
- if rehydrate_priority is not None:
1594
- header_parameters['x-ms-rehydrate-priority'] = self._client._serialize.header( # pylint: disable=protected-access
1595
- "rehydrate_priority", rehydrate_priority, 'str')
1596
- if lease_id is not None:
1597
- header_parameters['x-ms-lease-id'] = self._client._serialize.header("lease_id", lease_id, 'str') # pylint: disable=protected-access
1598
- if if_tags is not None:
1599
- header_parameters['x-ms-if-tags'] = self._client._serialize.header("if_tags", if_tags, 'str') # pylint: disable=protected-access
1600
-
1601
- return query_parameters, header_parameters
1602
-
1603
- def _generate_set_tiers_options(
1604
- self, blob_tier: Optional[Union[str, 'StandardBlobTier', 'PremiumPageBlobTier']],
1605
- *blobs: Union[str, Dict[str, Any], BlobProperties],
1606
- **kwargs: Any
1607
- ):
1608
- timeout = kwargs.pop('timeout', None)
1609
- raise_on_any_failure = kwargs.pop('raise_on_any_failure', True)
1610
- rehydrate_priority = kwargs.pop('rehydrate_priority', None)
1611
- if_tags = kwargs.pop('if_tags_match_condition', None)
1612
- kwargs.update({'raise_on_any_failure': raise_on_any_failure,
1613
- 'sas': self._query_str.replace('?', '&'),
1614
- 'timeout': '&timeout=' + str(timeout) if timeout else "",
1615
- 'path': self.container_name,
1616
- 'restype': 'restype=container&'
1617
- })
1618
-
1619
- reqs = []
1620
- for blob in blobs:
1621
- blob_name = _get_blob_name(blob)
1622
- container_name = self.container_name
1623
-
1624
- try:
1625
- tier = blob_tier or blob.get('blob_tier')
1626
- query_parameters, header_parameters = self._generate_set_tiers_subrequest_options(
1627
- tier=tier,
1628
- snapshot=blob.get('snapshot'),
1629
- version_id=blob.get('version_id'),
1630
- rehydrate_priority=rehydrate_priority or blob.get('rehydrate_priority'),
1631
- lease_access_conditions=blob.get('lease_id'),
1632
- if_tags=if_tags or blob.get('if_tags_match_condition'),
1633
- timeout=timeout or blob.get('timeout')
1634
- )
1635
- except AttributeError:
1636
- query_parameters, header_parameters = self._generate_set_tiers_subrequest_options(
1637
- blob_tier, rehydrate_priority=rehydrate_priority, if_tags=if_tags)
1638
-
1639
- req = HttpRequest(
1640
- "PUT",
1641
- f"/{quote(container_name)}/{quote(blob_name, safe='/~')}{self._query_str}",
1642
- headers=header_parameters
1643
- )
1644
- req.format_parameters(query_parameters)
1645
- reqs.append(req)
1646
-
1647
- return reqs, kwargs
1648
-
1649
1426
  @distributed_trace
1650
1427
  def set_standard_blob_tier_blobs(
1651
- self, standard_blob_tier: Optional[Union[str, 'StandardBlobTier']],
1428
+ self, standard_blob_tier: Optional[Union[str, "StandardBlobTier"]],
1652
1429
  *blobs: Union[str, Dict[str, Any], BlobProperties],
1653
1430
  **kwargs: Any
1654
1431
  ) -> Iterator["HttpResponse"]:
@@ -1717,13 +1494,19 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
1717
1494
  :return: An iterator of responses, one for each blob in order
1718
1495
  :rtype: Iterator[~azure.core.pipeline.transport.HttpResponse]
1719
1496
  """
1720
- reqs, options = self._generate_set_tiers_options(standard_blob_tier, *blobs, **kwargs)
1497
+ reqs, options = _generate_set_tiers_options(
1498
+ self._query_str,
1499
+ self.container_name,
1500
+ standard_blob_tier,
1501
+ self._client,
1502
+ *blobs,
1503
+ **kwargs)
1721
1504
 
1722
1505
  return self._batch_send(*reqs, **options)
1723
1506
 
1724
1507
  @distributed_trace
1725
1508
  def set_premium_page_blob_tier_blobs(
1726
- self, premium_page_blob_tier: Optional[Union[str, 'PremiumPageBlobTier']],
1509
+ self, premium_page_blob_tier: Optional[Union[str, "PremiumPageBlobTier"]],
1727
1510
  *blobs: Union[str, Dict[str, Any], BlobProperties],
1728
1511
  **kwargs: Any
1729
1512
  ) -> Iterator["HttpResponse"]:
@@ -1770,15 +1553,21 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
1770
1553
  :return: An iterator of responses, one for each blob in order
1771
1554
  :rtype: Iterator[~azure.core.pipeline.transport.HttpResponse]
1772
1555
  """
1773
- reqs, options = self._generate_set_tiers_options(premium_page_blob_tier, *blobs, **kwargs)
1556
+ reqs, options = _generate_set_tiers_options(
1557
+ self._query_str,
1558
+ self.container_name,
1559
+ premium_page_blob_tier,
1560
+ self._client,
1561
+ *blobs,
1562
+ **kwargs)
1774
1563
 
1775
1564
  return self._batch_send(*reqs, **options)
1776
1565
 
1777
1566
  def get_blob_client(
1778
- self, blob: str,
1779
- snapshot: Optional[str] = None,
1780
- *,
1781
- version_id: Optional[str] = None
1567
+ self, blob: str,
1568
+ snapshot: Optional[str] = None,
1569
+ *,
1570
+ version_id: Optional[str] = None
1782
1571
  ) -> BlobClient:
1783
1572
  """Get a client to interact with the specified blob.
1784
1573
 
@@ -1809,7 +1598,9 @@ class ContainerClient(StorageAccountHostsMixin, StorageEncryptionMixin): # py
1809
1598
  "Please use 'BlobProperties.name' or any other str input type instead.",
1810
1599
  DeprecationWarning
1811
1600
  )
1812
- blob_name = _get_blob_name(blob)
1601
+ blob_name = blob.get('name')
1602
+ else:
1603
+ blob_name = blob
1813
1604
  _pipeline = Pipeline(
1814
1605
  transport=TransportWrapper(self._pipeline._transport), # pylint: disable = protected-access
1815
1606
  policies=self._pipeline._impl_policies # pylint: disable = protected-access