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
@@ -11,47 +11,44 @@ from typing import (
11
11
  Any, Dict, List, Optional, Union,
12
12
  TYPE_CHECKING
13
13
  )
14
- from urllib.parse import urlparse
15
-
16
14
  from typing_extensions import Self
17
15
 
18
16
  from azure.core.exceptions import HttpResponseError
19
17
  from azure.core.paging import ItemPaged
20
18
  from azure.core.pipeline import Pipeline
21
19
  from azure.core.tracing.decorator import distributed_trace
22
- from ._shared.base_client import StorageAccountHostsMixin, TransportWrapper, parse_connection_str, parse_query
20
+ from ._blob_client import BlobClient
21
+ from ._blob_service_client_helpers import _parse_url
22
+ from ._container_client import ContainerClient
23
+ from ._deserialize import service_properties_deserialize, service_stats_deserialize
24
+ from ._encryption import StorageEncryptionMixin
25
+ from ._generated import AzureBlobStorage
26
+ from ._generated.models import KeyInfo, StorageServiceProperties
27
+ from ._list_blobs_helper import FilteredBlobPaged
28
+ from ._models import BlobProperties, ContainerProperties, ContainerPropertiesPaged, CorsRule
29
+ from ._serialize import get_api_version
30
+ from ._shared.base_client import parse_connection_str, parse_query, StorageAccountHostsMixin, TransportWrapper
23
31
  from ._shared.models import LocationMode
24
32
  from ._shared.parser import _to_utc_datetime
25
33
  from ._shared.response_handlers import (
26
- return_response_headers,
34
+ parse_to_internal_user_delegation_key,
27
35
  process_storage_error,
28
- parse_to_internal_user_delegation_key
36
+ return_response_headers
29
37
  )
30
- from ._generated import AzureBlobStorage
31
- from ._generated.models import StorageServiceProperties, KeyInfo
32
- from ._container_client import ContainerClient
33
- from ._blob_client import BlobClient
34
- from ._deserialize import service_stats_deserialize, service_properties_deserialize
35
- from ._encryption import StorageEncryptionMixin
36
- from ._list_blobs_helper import FilteredBlobPaged
37
- from ._models import BlobProperties, ContainerPropertiesPaged
38
- from ._serialize import get_api_version
39
38
 
40
39
  if TYPE_CHECKING:
41
40
  from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential, TokenCredential
42
41
  from datetime import datetime
43
- from ._shared.models import UserDelegationKey
44
42
  from ._lease import BlobLeaseClient
45
43
  from ._models import (
46
- ContainerProperties,
47
- PublicAccess,
48
44
  BlobAnalyticsLogging,
45
+ FilteredBlob,
49
46
  Metrics,
50
- CorsRule,
47
+ PublicAccess,
51
48
  RetentionPolicy,
52
- StaticWebsite,
53
- FilteredBlob
49
+ StaticWebsite
54
50
  )
51
+ from ._shared.models import UserDelegationKey
55
52
 
56
53
 
57
54
  class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
@@ -118,28 +115,20 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
118
115
  :end-before: [END create_blob_service_client_oauth]
119
116
  :language: python
120
117
  :dedent: 8
121
- :caption: Creating the BlobServiceClient with Azure Identity credentials.
118
+ :caption: Creating the BlobServiceClient with Default Azure Identity credentials.
122
119
  """
123
120
 
124
121
  def __init__(
125
- self, account_url: str,
126
- credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
127
- **kwargs: Any
128
- ) -> None:
129
- try:
130
- if not account_url.lower().startswith('http'):
131
- account_url = "https://" + account_url
132
- except AttributeError as exc:
133
- raise ValueError("Account URL must be a string.") from exc
134
- parsed_url = urlparse(account_url.rstrip('/'))
135
- if not parsed_url.netloc:
136
- raise ValueError(f"Invalid URL: {account_url}")
137
-
122
+ self, account_url: str,
123
+ credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
124
+ **kwargs: Any
125
+ ) -> None:
126
+ parsed_url, sas_token = _parse_url(account_url=account_url)
138
127
  _, sas_token = parse_query(parsed_url.query)
139
128
  self._query_str, credential = self._format_query_string(sas_token, credential)
140
129
  super(BlobServiceClient, self).__init__(parsed_url, service='blob', credential=credential, **kwargs)
141
130
  self._client = AzureBlobStorage(self.url, base_url=self.url, pipeline=self._pipeline)
142
- self._client._config.version = get_api_version(kwargs) # pylint: disable=protected-access
131
+ self._client._config.version = get_api_version(kwargs) # type: ignore [assignment] # pylint: disable=protected-access
143
132
  self._configure_encryption(kwargs)
144
133
 
145
134
  def _format_url(self, hostname):
@@ -155,10 +144,10 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
155
144
 
156
145
  @classmethod
157
146
  def from_connection_string(
158
- cls, conn_str: str,
159
- credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
160
- **kwargs: Any
161
- ) -> Self:
147
+ cls, conn_str: str,
148
+ credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long
149
+ **kwargs: Any
150
+ ) -> Self:
162
151
  """Create BlobServiceClient from a Connection String.
163
152
 
164
153
  :param str conn_str:
@@ -198,11 +187,11 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
198
187
  return cls(account_url, credential=credential, **kwargs)
199
188
 
200
189
  @distributed_trace
201
- def get_user_delegation_key(self, key_start_time, # type: datetime
202
- key_expiry_time, # type: datetime
203
- **kwargs # type: Any
204
- ):
205
- # type: (...) -> UserDelegationKey
190
+ def get_user_delegation_key(
191
+ self, key_start_time: "datetime",
192
+ key_expiry_time: "datetime",
193
+ **kwargs: Any
194
+ ) -> "UserDelegationKey":
206
195
  """
207
196
  Obtain a user delegation key for the purpose of signing SAS tokens.
208
197
  A token credential must be present on the service object for this request to succeed.
@@ -232,8 +221,7 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
232
221
  return parse_to_internal_user_delegation_key(user_delegation_key) # type: ignore
233
222
 
234
223
  @distributed_trace
235
- def get_account_information(self, **kwargs):
236
- # type: (Any) -> Dict[str, str]
224
+ def get_account_information(self, **kwargs: Any) -> Dict[str, str]:
237
225
  """Gets information related to the storage account.
238
226
 
239
227
  The information can also be retrieved if the user has a SAS to a container or blob.
@@ -257,8 +245,7 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
257
245
  process_storage_error(error)
258
246
 
259
247
  @distributed_trace
260
- def get_service_stats(self, **kwargs):
261
- # type: (**Any) -> Dict[str, Any]
248
+ def get_service_stats(self, **kwargs: Any) -> Dict[str, Any]:
262
249
  """Retrieves statistics related to replication for the Blob service.
263
250
 
264
251
  It is only available when read-access geo-redundant replication is enabled for
@@ -304,8 +291,7 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
304
291
  process_storage_error(error)
305
292
 
306
293
  @distributed_trace
307
- def get_service_properties(self, **kwargs):
308
- # type: (Any) -> Dict[str, Any]
294
+ def get_service_properties(self, **kwargs: Any) -> Dict[str, Any]:
309
295
  """Gets the properties of a storage account's Blob service, including
310
296
  Azure Storage Analytics.
311
297
 
@@ -337,16 +323,15 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
337
323
 
338
324
  @distributed_trace
339
325
  def set_service_properties(
340
- self, analytics_logging=None, # type: Optional[BlobAnalyticsLogging]
341
- hour_metrics=None, # type: Optional[Metrics]
342
- minute_metrics=None, # type: Optional[Metrics]
343
- cors=None, # type: Optional[List[CorsRule]]
344
- target_version=None, # type: Optional[str]
345
- delete_retention_policy=None, # type: Optional[RetentionPolicy]
346
- static_website=None, # type: Optional[StaticWebsite]
347
- **kwargs
348
- ):
349
- # type: (...) -> None
326
+ self, analytics_logging: Optional["BlobAnalyticsLogging"] = None,
327
+ hour_metrics: Optional["Metrics"] = None,
328
+ minute_metrics: Optional["Metrics"] = None,
329
+ cors: Optional[List[CorsRule]] = None,
330
+ target_version: Optional[str] = None,
331
+ delete_retention_policy: Optional["RetentionPolicy"] = None,
332
+ static_website: Optional["StaticWebsite"] = None,
333
+ **kwargs: Any
334
+ ) -> None:
350
335
  """Sets the properties of a storage account's Blob service, including
351
336
  Azure Storage Analytics.
352
337
 
@@ -406,7 +391,7 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
406
391
  logging=analytics_logging,
407
392
  hour_metrics=hour_metrics,
408
393
  minute_metrics=minute_metrics,
409
- cors=cors,
394
+ cors=CorsRule._to_generated(cors), # pylint: disable=protected-access
410
395
  default_service_version=target_version,
411
396
  delete_retention_policy=delete_retention_policy,
412
397
  static_website=static_website
@@ -419,11 +404,10 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
419
404
 
420
405
  @distributed_trace
421
406
  def list_containers(
422
- self, name_starts_with=None, # type: Optional[str]
423
- include_metadata=False, # type: Optional[bool]
424
- **kwargs
425
- ):
426
- # type: (...) -> ItemPaged[ContainerProperties]
407
+ self, name_starts_with: Optional[str] = None,
408
+ include_metadata: bool = False,
409
+ **kwargs: Any
410
+ ) -> ItemPaged[ContainerProperties]:
427
411
  """Returns a generator to list the containers under the specified account.
428
412
 
429
413
  The generator will lazily follow the continuation tokens returned by
@@ -487,8 +471,7 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
487
471
  )
488
472
 
489
473
  @distributed_trace
490
- def find_blobs_by_tags(self, filter_expression, **kwargs):
491
- # type: (str, **Any) -> ItemPaged[FilteredBlob]
474
+ def find_blobs_by_tags(self, filter_expression: str, **kwargs: Any) -> ItemPaged["FilteredBlob"]:
492
475
  """The Filter Blobs operation enables callers to list blobs across all
493
476
  containers whose tags match a given search expression. Filter blobs
494
477
  searches across all containers within a storage account but can be
@@ -523,12 +506,11 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
523
506
 
524
507
  @distributed_trace
525
508
  def create_container(
526
- self, name, # type: str
527
- metadata=None, # type: Optional[Dict[str, str]]
528
- public_access=None, # type: Optional[Union[PublicAccess, str]]
529
- **kwargs
530
- ):
531
- # type: (...) -> ContainerClient
509
+ self, name: str,
510
+ metadata: Optional[Dict[str, str]] = None,
511
+ public_access: Optional[Union["PublicAccess", str]] = None,
512
+ **kwargs: Any
513
+ ) -> ContainerClient:
532
514
  """Creates a new container under the specified account.
533
515
 
534
516
  If the container with the same name already exists, a ResourceExistsError will
@@ -577,7 +559,7 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
577
559
 
578
560
  @distributed_trace
579
561
  def delete_container(
580
- self, container: Union["ContainerProperties", str],
562
+ self, container: Union[ContainerProperties, str],
581
563
  lease: Optional[Union["BlobLeaseClient", str]] = None,
582
564
  **kwargs: Any
583
565
  ) -> None:
@@ -628,17 +610,16 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
628
610
  :dedent: 12
629
611
  :caption: Deleting a container in the blob service.
630
612
  """
631
- container = self.get_container_client(container) # type: ignore
613
+ container_client = self.get_container_client(container)
632
614
  kwargs.setdefault('merge_span', True)
633
615
  timeout = kwargs.pop('timeout', None)
634
- container.delete_container( # type: ignore
616
+ container_client.delete_container(
635
617
  lease=lease,
636
618
  timeout=timeout,
637
619
  **kwargs)
638
620
 
639
621
  @distributed_trace
640
- def _rename_container(self, name, new_name, **kwargs):
641
- # type: (str, str, **Any) -> ContainerClient
622
+ def _rename_container(self, name: str, new_name: str, **kwargs: Any) -> ContainerClient:
642
623
  """Renames a container.
643
624
 
644
625
  Operation is successful only if the source container exists.
@@ -663,18 +644,21 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
663
644
  renamed_container = self.get_container_client(new_name)
664
645
  lease = kwargs.pop('lease', None)
665
646
  try:
666
- kwargs['source_lease_id'] = lease.id # type: str
647
+ kwargs['source_lease_id'] = lease.id
667
648
  except AttributeError:
668
649
  kwargs['source_lease_id'] = lease
669
650
  try:
670
- renamed_container._client.container.rename(name, **kwargs) # pylint: disable = protected-access
651
+ renamed_container._client.container.rename(name, **kwargs) # pylint: disable = protected-access
671
652
  return renamed_container
672
653
  except HttpResponseError as error:
673
654
  process_storage_error(error)
674
655
 
675
656
  @distributed_trace
676
- def undelete_container(self, deleted_container_name, deleted_container_version, **kwargs):
677
- # type: (str, str, **Any) -> ContainerClient
657
+ def undelete_container(
658
+ self, deleted_container_name: str,
659
+ deleted_container_version: str,
660
+ **kwargs: Any
661
+ ) -> ContainerClient:
678
662
  """Restores soft-deleted container.
679
663
 
680
664
  Operation will only be successful if used within the specified number of days
@@ -708,8 +692,7 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
708
692
  except HttpResponseError as error:
709
693
  process_storage_error(error)
710
694
 
711
- def get_container_client(self, container):
712
- # type: (Union[ContainerProperties, str]) -> ContainerClient
695
+ def get_container_client(self, container: Union[ContainerProperties, str]) -> ContainerClient:
713
696
  """Get a client to interact with the specified container.
714
697
 
715
698
  The container need not already exist.
@@ -730,9 +713,9 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
730
713
  :dedent: 8
731
714
  :caption: Getting the container client to interact with a specific container.
732
715
  """
733
- try:
716
+ if isinstance(container, ContainerProperties):
734
717
  container_name = container.name
735
- except AttributeError:
718
+ else:
736
719
  container_name = container
737
720
  _pipeline = Pipeline(
738
721
  transport=TransportWrapper(self._pipeline._transport), # pylint: disable = protected-access
@@ -746,13 +729,12 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
746
729
  key_encryption_key=self.key_encryption_key, key_resolver_function=self.key_resolver_function)
747
730
 
748
731
  def get_blob_client(
749
- self, container: Union["ContainerProperties", str],
750
- blob: str,
751
- snapshot: Optional[Union[Dict[str, Any], str]] = None,
752
- *,
753
- version_id: Optional[str] = None
754
- ):
755
- # type: (...) -> BlobClient
732
+ self, container: Union[ContainerProperties, str],
733
+ blob: str,
734
+ snapshot: Optional[Union[Dict[str, Any], str]] = None,
735
+ *,
736
+ version_id: Optional[str] = None
737
+ ) -> BlobClient:
756
738
  """Get a client to interact with the specified blob.
757
739
 
758
740
  The blob need not already exist.
@@ -786,19 +768,18 @@ class BlobServiceClient(StorageAccountHostsMixin, StorageEncryptionMixin):
786
768
  "Please use 'BlobProperties.name' or any other str input type instead.",
787
769
  DeprecationWarning
788
770
  )
789
- try:
790
- container_name = container.name
791
- except AttributeError:
792
- container_name = container
793
- try:
794
771
  blob_name = blob.name
795
- except AttributeError:
772
+ else:
796
773
  blob_name = blob
774
+ if isinstance(container, ContainerProperties):
775
+ container_name = container.name
776
+ else:
777
+ container_name = container
797
778
  _pipeline = Pipeline(
798
779
  transport=TransportWrapper(self._pipeline._transport), # pylint: disable = protected-access
799
780
  policies=self._pipeline._impl_policies # pylint: disable = protected-access
800
781
  )
801
- return BlobClient( # type: ignore
782
+ return BlobClient(
802
783
  self.url, container_name=container_name, blob_name=blob_name, snapshot=snapshot,
803
784
  credential=self.credential, api_version=self.api_version, _configuration=self._config,
804
785
  _pipeline=_pipeline, _location_mode=self._location_mode, _hosts=self._hosts,
@@ -0,0 +1,27 @@
1
+ # -------------------------------------------------------------------------
2
+ # Copyright (c) Microsoft Corporation. All rights reserved.
3
+ # Licensed under the MIT License. See License.txt in the project root for
4
+ # license information.
5
+ # --------------------------------------------------------------------------
6
+
7
+ from typing import Any, Tuple, TYPE_CHECKING
8
+ from urllib.parse import urlparse
9
+ from ._shared.base_client import parse_query
10
+
11
+ if TYPE_CHECKING:
12
+ from urllib.parse import ParseResult
13
+
14
+
15
+ def _parse_url(account_url: str) -> Tuple["ParseResult", Any]:
16
+ try:
17
+ if not account_url.lower().startswith('http'):
18
+ account_url = "https://" + account_url
19
+ except AttributeError as exc:
20
+ raise ValueError("Account URL must be a string.") from exc
21
+ parsed_url = urlparse(account_url.rstrip('/'))
22
+ if not parsed_url.netloc:
23
+ raise ValueError(f"Invalid URL: {account_url}")
24
+
25
+ _, sas_token = parse_query(parsed_url.query)
26
+
27
+ return parsed_url, sas_token