Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-azure-storage-blob for openSUSE:Factory checked in at 2023-11-10 12:33:47 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-azure-storage-blob (Old) and /work/SRC/openSUSE:Factory/.python-azure-storage-blob.new.17445 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-azure-storage-blob" Fri Nov 10 12:33:47 2023 rev:29 rq:1124839 version:12.19.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-azure-storage-blob/python-azure-storage-blob.changes 2023-10-12 11:52:18.947245297 +0200 +++ /work/SRC/openSUSE:Factory/.python-azure-storage-blob.new.17445/python-azure-storage-blob.changes 2023-11-10 12:37:37.530042776 +0100 @@ -1,0 +2,8 @@ +Fri Nov 10 09:10:20 UTC 2023 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- New upstream release + + Version 12.19.0 + + For detailed information about changes see the + CHANGELOG.md file provided with this package + +------------------------------------------------------------------- Old: ---- azure-storage-blob-12.18.3.tar.gz New: ---- azure-storage-blob-12.19.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-azure-storage-blob.spec ++++++ --- /var/tmp/diff_new_pack.JGhhzX/_old 2023-11-10 12:37:38.134065131 +0100 +++ /var/tmp/diff_new_pack.JGhhzX/_new 2023-11-10 12:37:38.134065131 +0100 @@ -21,7 +21,7 @@ %define skip_python2 1 %endif Name: python-azure-storage-blob -Version: 12.18.3 +Version: 12.19.0 Release: 0 Summary: Microsoft Azure Storage Blob Client Library for Python License: MIT ++++++ azure-storage-blob-12.18.3.tar.gz -> azure-storage-blob-12.19.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/CHANGELOG.md new/azure-storage-blob-12.19.0/CHANGELOG.md --- old/azure-storage-blob-12.18.3/CHANGELOG.md 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/CHANGELOG.md 2023-11-07 23:29:15.000000000 +0100 @@ -1,5 +1,24 @@ # Release History +## 12.19.0 (2023-11-07) + +### Features Added +- Stable release of features from 12.19.0b1 + +## 12.19.0b1 (2023-10-17) + +### Features Added +- Added support for service version 2023-11-03. +- Added `audience` as an optional keyword that can be specified on APIs that have a `credential` parameter. This +keyword only has an effect when the credential provided is of type `TokenCredential`. + +### Bugs Fixed +- Deprecated `BlobProperties` as a valid input type to the `blob` parameter on the following APIs: +BlobServiceClient's `get_blob_client`, ContainerClient's `delete_blob`, `download_blob`, and `get_blob_client`. +This deprecation change also applies to the `name` parameter on ContainerClient's `upload_blob` API. This change +applies to both sync and async packages but does not apply to the batch equivalent of any of the listed APIs. If a +`BlobProperties` is provided, a deprecation warning is raised. + ## 12.18.3 (2023-10-10) ### Bugs Fixed diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/PKG-INFO new/azure-storage-blob-12.19.0/PKG-INFO --- old/azure-storage-blob-12.18.3/PKG-INFO 2023-10-10 23:34:56.812399400 +0200 +++ new/azure-storage-blob-12.19.0/PKG-INFO 2023-11-07 23:30:02.553336100 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: azure-storage-blob -Version: 12.18.3 +Version: 12.19.0 Summary: Microsoft Azure Blob Storage Client Library for Python Home-page: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob Author: Microsoft Corporation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure/storage/blob/_blob_client.py new/azure-storage-blob-12.19.0/azure/storage/blob/_blob_client.py --- old/azure-storage-blob-12.18.3/azure/storage/blob/_blob_client.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure/storage/blob/_blob_client.py 2023-11-07 23:29:15.000000000 +0100 @@ -136,6 +136,9 @@ or 4MB. :keyword str version_id: The version id parameter is an opaque DateTime value that, when present, specifies the version of the blob to operate on. + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net. .. admonition:: Example: @@ -241,6 +244,9 @@ the snapshot in the url. :keyword str version_id: The version id parameter is an opaque DateTime value that, when present, specifies the version of the blob to operate on. + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net. :returns: A Blob client. :rtype: ~azure.storage.blob.BlobClient """ @@ -323,6 +329,9 @@ :type credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] # pylint: disable=line-too-long :keyword str version_id: The version id parameter is an opaque DateTime value that, when present, specifies the version of the blob to operate on. + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net. :returns: A Blob client. :rtype: ~azure.storage.blob.BlobClient @@ -1014,6 +1023,10 @@ treat the blob data as CSV data formatted in the default dialect. This can be overridden with a custom DelimitedTextDialect, or DelimitedJsonDialect or "ParquetDialect" (passed as a string or enum). These dialects can be passed through their respective classes, the QuickQueryDialect enum or as a string + + .. note:: + "ParquetDialect" is in preview, so some features may not work as intended. + :paramtype blob_format: ~azure.storage.blob.DelimitedTextDialect or ~azure.storage.blob.DelimitedJsonDialect or ~azure.storage.blob.QuickQueryDialect or str :keyword output_format: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure/storage/blob/_blob_service_client.py new/azure-storage-blob-12.19.0/azure/storage/blob/_blob_service_client.py --- old/azure-storage-blob-12.18.3/azure/storage/blob/_blob_service_client.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure/storage/blob/_blob_service_client.py 2023-11-07 23:29:15.000000000 +0100 @@ -33,7 +33,7 @@ from ._deserialize import service_stats_deserialize, service_properties_deserialize from ._encryption import StorageEncryptionMixin from ._list_blobs_helper import FilteredBlobPaged -from ._models import ContainerPropertiesPaged +from ._models import BlobProperties, ContainerPropertiesPaged from ._serialize import get_api_version if TYPE_CHECKING: @@ -43,7 +43,6 @@ from ._lease import BlobLeaseClient from ._models import ( ContainerProperties, - BlobProperties, PublicAccess, BlobAnalyticsLogging, Metrics, @@ -100,6 +99,9 @@ the exceeded part will be downloaded in chunks (could be parallel). Defaults to 32*1024*1024, or 32MB. :keyword int max_chunk_get_size: The maximum chunk size used for downloading a blob. Defaults to 4*1024*1024, or 4MB. + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net. .. admonition:: Example: @@ -170,6 +172,9 @@ If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" should be the storage account key. :paramtype credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] # pylint: disable=line-too-long + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net. :returns: A Blob service client. :rtype: ~azure.storage.blob.BlobServiceClient @@ -566,11 +571,10 @@ @distributed_trace def delete_container( - self, container, # type: Union[ContainerProperties, str] - lease=None, # type: Optional[Union[BlobLeaseClient, str]] - **kwargs - ): - # type: (...) -> None + self, container: Union["ContainerProperties", str], + lease: Optional[Union["BlobLeaseClient", str]] = None, + **kwargs: Any + ) -> None: """Marks the specified container for deletion. The container and any blobs contained within it are later deleted during garbage collection. @@ -736,11 +740,11 @@ key_encryption_key=self.key_encryption_key, key_resolver_function=self.key_resolver_function) def get_blob_client( - self, container, # type: Union[ContainerProperties, str] - blob, # type: Union[BlobProperties, str] - snapshot=None, # type: Optional[Union[Dict[str, Any], str]] + self, container: Union["ContainerProperties", str], + blob: str, + snapshot: Optional[Union[Dict[str, Any], str]] = None, *, - version_id=None # type: Optional[str] + version_id: Optional[str] = None ): # type: (...) -> BlobClient """Get a client to interact with the specified blob. @@ -751,10 +755,7 @@ The container that the blob is in. This can either be the name of the container, or an instance of ContainerProperties. :type container: str or ~azure.storage.blob.ContainerProperties - :param blob: - The blob with which to interact. This can either be the name of the blob, - or an instance of BlobProperties. - :type blob: str or ~azure.storage.blob.BlobProperties + :param str blob: The name of the blob with which to interact. :param snapshot: The optional blob snapshot on which to operate. This can either be the ID of the snapshot, or a dictionary output returned by :func:`~azure.storage.blob.BlobClient.create_snapshot()`. @@ -773,6 +774,12 @@ :dedent: 12 :caption: Getting the blob client to interact with a specific blob. """ + if isinstance(blob, BlobProperties): + warnings.warn( + "The use of a 'BlobProperties' instance for param blob is deprecated. " + + "Please use 'BlobProperties.name' or any other str input type instead.", + DeprecationWarning + ) try: container_name = container.name except AttributeError: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure/storage/blob/_container_client.py new/azure-storage-blob-12.19.0/azure/storage/blob/_container_client.py --- old/azure-storage-blob-12.18.3/azure/storage/blob/_container_client.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure/storage/blob/_container_client.py 2023-11-07 23:29:15.000000000 +0100 @@ -6,6 +6,7 @@ # -------------------------------------------------------------------------- import functools +import warnings from typing import ( Any, AnyStr, Dict, List, IO, Iterable, Iterator, Optional, overload, Union, TYPE_CHECKING @@ -18,7 +19,7 @@ from azure.core.exceptions import HttpResponseError, ResourceNotFoundError from azure.core.paging import ItemPaged from azure.core.pipeline import Pipeline -from azure.core.pipeline.transport import HttpRequest, HttpResponse +from azure.core.pipeline.transport import HttpRequest from azure.core.tracing.decorator import distributed_trace from ._shared.base_client import StorageAccountHostsMixin, TransportWrapper, parse_connection_str, parse_query from ._shared.request_handlers import add_metadata_headers, serialize_iso @@ -51,6 +52,7 @@ if TYPE_CHECKING: from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential, TokenCredential + from azure.core.pipeline.transport import HttpResponse # pylint: disable=C4756 from datetime import datetime from ._models import ( # pylint: disable=unused-import PublicAccess, @@ -120,6 +122,9 @@ the exceeded part will be downloaded in chunks (could be parallel). Defaults to 32*1024*1024, or 32MB. :keyword int max_chunk_get_size: The maximum chunk size used for downloading a blob. Defaults to 4*1024*1024, or 4MB. + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net. .. admonition:: Example: @@ -198,6 +203,9 @@ If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" should be the storage account key. :paramtype credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net. :returns: A container client. :rtype: ~azure.storage.blob.ContainerClient """ @@ -244,6 +252,9 @@ If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" should be the storage account key. :paramtype credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net. :returns: A container client. :rtype: ~azure.storage.blob.ContainerClient @@ -958,7 +969,7 @@ @distributed_trace def upload_blob( - self, name: Union[str, BlobProperties], + self, name: str, data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]], blob_type: Union[str, BlobType] = BlobType.BlockBlob, length: Optional[int] = None, @@ -967,9 +978,7 @@ ) -> BlobClient: """Creates a new blob from a data source with automatic chunking. - :param name: The blob with which to interact. If specified, this value will override - a blob value specified in the blob URL. - :type name: str or ~azure.storage.blob.BlobProperties + :param str name: The blob with which to interact. :param data: The blob data to upload. :param ~azure.storage.blob.BlobType blob_type: The type of the blob. This can be either BlockBlob, PageBlob or AppendBlob. The default value is BlockBlob. @@ -1079,6 +1088,12 @@ :dedent: 8 :caption: Upload blob to the container. """ + if isinstance(name, BlobProperties): + warnings.warn( + "The use of a 'BlobProperties' instance for param name is deprecated. " + + "Please use 'BlobProperties.name' or any other str input type instead.", + DeprecationWarning + ) blob = self.get_blob_client(name) kwargs.setdefault('merge_span', True) timeout = kwargs.pop('timeout', None) @@ -1096,9 +1111,9 @@ @distributed_trace def delete_blob( - self, blob, # type: Union[str, BlobProperties] - delete_snapshots=None, # type: Optional[str] - **kwargs + self, blob: str, + delete_snapshots: Optional[str] = None, + **kwargs: Any ): # type: (...) -> None """Marks the specified blob or snapshot for deletion. @@ -1114,9 +1129,7 @@ Soft deleted blob or snapshot is accessible through :func:`list_blobs()` specifying `include=["deleted"]` option. Soft-deleted blob or snapshot can be restored using :func:`~azure.storage.blob.BlobClient.undelete()` - :param blob: The blob with which to interact. If specified, this value will override - a blob value specified in the blob URL. - :type blob: str or ~azure.storage.blob.BlobProperties + :param str blob: The blob with which to interact. :param str delete_snapshots: Required if the blob has associated snapshots. Values include: - "only": Deletes only the blobs snapshots. @@ -1163,6 +1176,12 @@ #other-client--per-operation-configuration>`_. :rtype: None """ + if isinstance(blob, BlobProperties): + warnings.warn( + "The use of a 'BlobProperties' instance for param blob is deprecated. " + + "Please use 'BlobProperties.name' or any other str input type instead.", + DeprecationWarning + ) blob_client = self.get_blob_client(blob) # type: ignore kwargs.setdefault('merge_span', True) timeout = kwargs.pop('timeout', None) @@ -1173,39 +1192,40 @@ @overload def download_blob( - self, blob: Union[str, BlobProperties], + self, blob: str, offset: int = None, length: int = None, *, encoding: str, - **kwargs) -> StorageStreamDownloader[str]: + **kwargs: Any + ) -> StorageStreamDownloader[str]: ... @overload def download_blob( - self, blob: Union[str, BlobProperties], + self, blob: str, offset: int = None, length: int = None, *, encoding: None = None, - **kwargs) -> StorageStreamDownloader[bytes]: + **kwargs: Any + ) -> StorageStreamDownloader[bytes]: ... @distributed_trace def download_blob( - self, blob: Union[str, BlobProperties], + self, blob: str, offset: int = None, length: int = None, *, encoding: Optional[str] = None, - **kwargs) -> StorageStreamDownloader: + **kwargs: Any + ) -> StorageStreamDownloader: """Downloads a blob to the StorageStreamDownloader. The readall() method must be used to read all the content or readinto() must be used to download the blob into a stream. Using chunks() returns an iterator which allows the user to iterate over the content in chunks. - :param blob: The blob with which to interact. If specified, this value will override - a blob value specified in the blob URL. - :type blob: str or ~azure.storage.blob.BlobProperties + :param str blob: The blob with which to interact. :param int offset: Start of byte range to use for downloading a section of the blob. Must be set if length is provided. @@ -1282,6 +1302,12 @@ :returns: A streaming object (StorageStreamDownloader) :rtype: ~azure.storage.blob.StorageStreamDownloader """ + if isinstance(blob, BlobProperties): + warnings.warn( + "The use of a 'BlobProperties' instance for param blob is deprecated. " + + "Please use 'BlobProperties.name' or any other str input type instead.", + DeprecationWarning + ) blob_client = self.get_blob_client(blob) # type: ignore kwargs.setdefault('merge_span', True) return blob_client.download_blob( @@ -1414,7 +1440,7 @@ def delete_blobs( # pylint: disable=delete-operation-wrong-return-type self, *blobs: Union[str, Dict[str, Any], BlobProperties], **kwargs: Any - ) -> Iterator[HttpResponse]: + ) -> Iterator["HttpResponse"]: """Marks the specified blobs or snapshots for deletion. The blobs are later deleted during garbage collection. @@ -1599,7 +1625,7 @@ self, standard_blob_tier: Optional[Union[str, 'StandardBlobTier']], *blobs: Union[str, Dict[str, Any], BlobProperties], **kwargs: Any - ) -> Iterator[HttpResponse]: + ) -> Iterator["HttpResponse"]: """This operation sets the tier on block blobs. A block blob's tier determines Hot/Cool/Archive storage type. @@ -1674,7 +1700,7 @@ self, premium_page_blob_tier: Optional[Union[str, 'PremiumPageBlobTier']], *blobs: Union[str, Dict[str, Any], BlobProperties], **kwargs: Any - ) -> Iterator[HttpResponse]: + ) -> Iterator["HttpResponse"]: """Sets the page blob tiers on all blobs. This API is only supported for page blobs on premium accounts. The maximum number of blobs that can be updated in a single request is 256. @@ -1716,26 +1742,24 @@ This is a boolean param which defaults to True. When this is set, an exception is raised even if there is a single operation failure. :return: An iterator of responses, one for each blob in order - :rtype: iterator[~azure.core.pipeline.transport.HttpResponse] + :rtype: Iterator[~azure.core.pipeline.transport.HttpResponse] """ reqs, options = self._generate_set_tiers_options(premium_page_blob_tier, *blobs, **kwargs) return self._batch_send(*reqs, **options) def get_blob_client( - self, blob, # type: Union[str, BlobProperties] - snapshot=None, # type: str + self, blob: str, + snapshot: Optional[str] = None, *, - version_id=None # type: Optional[str] - ): - # type: (...) -> BlobClient + version_id: Optional[str] = None + ) -> BlobClient: """Get a client to interact with the specified blob. The blob need not already exist. - :param blob: + :param str blob: The blob with which to interact. - :type blob: str or ~azure.storage.blob.BlobProperties :param str snapshot: The optional blob snapshot on which to operate. This can be the snapshot ID string or the response returned from :func:`~BlobClient.create_snapshot()`. @@ -1753,6 +1777,12 @@ :dedent: 8 :caption: Get the blob client. """ + if isinstance(blob, BlobProperties): + warnings.warn( + "The use of a 'BlobProperties' instance for param blob is deprecated. " + + "Please use 'BlobProperties.name' or any other str input type instead.", + DeprecationWarning + ) blob_name = _get_blob_name(blob) _pipeline = Pipeline( transport=TransportWrapper(self._pipeline._transport), # pylint: disable = protected-access diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure/storage/blob/_serialize.py new/azure-storage-blob-12.19.0/azure/storage/blob/_serialize.py --- old/azure-storage-blob-12.18.3/azure/storage/blob/_serialize.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure/storage/blob/_serialize.py 2023-11-07 23:29:15.000000000 +0100 @@ -56,6 +56,7 @@ '2023-01-03', '2023-05-03', '2023-08-03', + '2023-11-03', ] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure/storage/blob/_shared/base_client.py new/azure-storage-blob-12.19.0/azure/storage/blob/_shared/base_client.py --- old/azure-storage-blob-12.18.3/azure/storage/blob/_shared/base_client.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure/storage/blob/_shared/base_client.py 2023-11-07 23:29:15.000000000 +0100 @@ -35,7 +35,7 @@ UserAgentPolicy, ) -from .constants import CONNECTION_TIMEOUT, READ_TIMEOUT, SERVICE_HOST_BASE +from .constants import CONNECTION_TIMEOUT, DEFAULT_OAUTH_SCOPE, READ_TIMEOUT, SERVICE_HOST_BASE, STORAGE_OAUTH_SCOPE from .models import LocationMode from .authentication import SharedKeyCredentialPolicy from .shared_access_signature import QueryStringConstants @@ -221,7 +221,11 @@ # type: (Any, **Any) -> Tuple[Configuration, Pipeline] self._credential_policy = None if hasattr(credential, "get_token"): - self._credential_policy = StorageBearerTokenCredentialPolicy(credential) + if kwargs.get('audience'): + audience = str(kwargs.pop('audience')).rstrip('/') + DEFAULT_OAUTH_SCOPE + else: + audience = STORAGE_OAUTH_SCOPE + self._credential_policy = StorageBearerTokenCredentialPolicy(credential, audience) elif isinstance(credential, SharedKeyCredentialPolicy): self._credential_policy = credential elif isinstance(credential, AzureSasCredential): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure/storage/blob/_shared/base_client_async.py new/azure-storage-blob-12.19.0/azure/storage/blob/_shared/base_client_async.py --- old/azure-storage-blob-12.18.3/azure/storage/blob/_shared/base_client_async.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure/storage/blob/_shared/base_client_async.py 2023-11-07 23:29:15.000000000 +0100 @@ -23,7 +23,7 @@ ) from azure.core.pipeline.transport import AsyncHttpTransport -from .constants import CONNECTION_TIMEOUT, READ_TIMEOUT +from .constants import CONNECTION_TIMEOUT, DEFAULT_OAUTH_SCOPE, READ_TIMEOUT, STORAGE_OAUTH_SCOPE from .authentication import SharedKeyCredentialPolicy from .base_client import create_configuration from .policies import ( @@ -68,8 +68,12 @@ def _create_pipeline(self, credential, **kwargs): # type: (Any, **Any) -> Tuple[Configuration, Pipeline] self._credential_policy = None - if hasattr(credential, 'get_token'): - self._credential_policy = AsyncStorageBearerTokenCredentialPolicy(credential) + if hasattr(credential, "get_token"): + if kwargs.get('audience'): + audience = str(kwargs.pop('audience')).rstrip('/') + DEFAULT_OAUTH_SCOPE + else: + audience = STORAGE_OAUTH_SCOPE + self._credential_policy = AsyncStorageBearerTokenCredentialPolicy(credential, audience) elif isinstance(credential, SharedKeyCredentialPolicy): self._credential_policy = credential elif isinstance(credential, AzureSasCredential): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure/storage/blob/_shared/policies.py new/azure-storage-blob-12.19.0/azure/storage/blob/_shared/policies.py --- old/azure-storage-blob-12.18.3/azure/storage/blob/_shared/policies.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure/storage/blob/_shared/policies.py 2023-11-07 23:29:15.000000000 +0100 @@ -40,7 +40,7 @@ from azure.core.exceptions import AzureError, ServiceRequestError, ServiceResponseError from .authentication import StorageHttpChallenge -from .constants import DEFAULT_OAUTH_SCOPE, STORAGE_OAUTH_SCOPE +from .constants import DEFAULT_OAUTH_SCOPE from .models import LocationMode try: @@ -647,9 +647,8 @@ class StorageBearerTokenCredentialPolicy(BearerTokenCredentialPolicy): """ Custom Bearer token credential policy for following Storage Bearer challenges """ - def __init__(self, credential, **kwargs): - # type: (TokenCredential, **Any) -> None - super(StorageBearerTokenCredentialPolicy, self).__init__(credential, STORAGE_OAUTH_SCOPE, **kwargs) + def __init__(self, credential: "TokenCredential", audience: str, **kwargs: Any) -> None: + super(StorageBearerTokenCredentialPolicy, self).__init__(credential, audience, **kwargs) def on_challenge(self, request, response): # type: (PipelineRequest, PipelineResponse) -> bool diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure/storage/blob/_shared/policies_async.py new/azure-storage-blob-12.19.0/azure/storage/blob/_shared/policies_async.py --- old/azure-storage-blob-12.18.3/azure/storage/blob/_shared/policies_async.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure/storage/blob/_shared/policies_async.py 2023-11-07 23:29:15.000000000 +0100 @@ -14,7 +14,7 @@ from azure.core.exceptions import AzureError from .authentication import StorageHttpChallenge -from .constants import DEFAULT_OAUTH_SCOPE, STORAGE_OAUTH_SCOPE +from .constants import DEFAULT_OAUTH_SCOPE from .policies import is_retry, StorageRetryPolicy if TYPE_CHECKING: @@ -237,9 +237,8 @@ class AsyncStorageBearerTokenCredentialPolicy(AsyncBearerTokenCredentialPolicy): """ Custom Bearer token credential policy for following Storage Bearer challenges """ - def __init__(self, credential, **kwargs): - # type: (AsyncTokenCredential, **Any) -> None - super(AsyncStorageBearerTokenCredentialPolicy, self).__init__(credential, STORAGE_OAUTH_SCOPE, **kwargs) + def __init__(self, credential: "AsyncTokenCredential", audience: str, **kwargs: Any) -> None: + super(AsyncStorageBearerTokenCredentialPolicy, self).__init__(credential, audience, **kwargs) async def on_challenge(self, request, response): # type: (PipelineRequest, PipelineResponse) -> bool diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure/storage/blob/_shared_access_signature.py new/azure-storage-blob-12.19.0/azure/storage/blob/_shared_access_signature.py --- old/azure-storage-blob-12.18.3/azure/storage/blob/_shared_access_signature.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure/storage/blob/_shared_access_signature.py 2023-11-07 23:29:15.000000000 +0100 @@ -311,7 +311,7 @@ account_key, # type: str resource_types, # type: Union[ResourceTypes, str] permission, # type: Union[AccountSasPermissions, str] - expiry, # type: Optional[Union[datetime, str]] + expiry, # type: Union[datetime, str] start=None, # type: Optional[Union[datetime, str]] ip=None, # type: Optional[str] **kwargs # type: Any @@ -331,17 +331,11 @@ :param permission: The permissions associated with the shared access signature. The user is restricted to operations allowed by the permissions. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has been - specified in an associated stored access policy. :type permission: str or ~azure.storage.blob.AccountSasPermissions :param expiry: The time at which the shared access signature becomes invalid. - Required unless an id is given referencing a stored access policy - which contains this field. This field must be omitted if it has - been specified in an associated stored access policy. Azure will always - convert values to UTC. If a date is passed in without timezone info, it - is assumed to be UTC. + Azure will always convert values to UTC. If a date is passed in + without timezone info, it is assumed to be UTC. :type expiry: ~datetime.datetime or str :param start: The time at which the shared access signature becomes valid. If @@ -481,6 +475,11 @@ :dedent: 12 :caption: Generating a sas token. """ + if not policy_id: + if not expiry: + raise ValueError("'expiry' parameter must be provided when not using a stored access policy.") + if not permission: + raise ValueError("'permission' parameter must be provided when not using a stored access policy.") if not user_delegation_key and not account_key: raise ValueError("Either user_delegation_key or account_key must be provided.") if isinstance(account_key, UserDelegationKey): @@ -602,6 +601,11 @@ :return: A Shared Access Signature (sas) token. :rtype: str """ + if not policy_id: + if not expiry: + raise ValueError("'expiry' parameter must be provided when not using a stored access policy.") + if not permission: + raise ValueError("'permission' parameter must be provided when not using a stored access policy.") if not user_delegation_key and not account_key: raise ValueError("Either user_delegation_key or account_key must be provided.") if isinstance(account_key, UserDelegationKey): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure/storage/blob/_version.py new/azure-storage-blob-12.19.0/azure/storage/blob/_version.py --- old/azure-storage-blob-12.18.3/azure/storage/blob/_version.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure/storage/blob/_version.py 2023-11-07 23:29:15.000000000 +0100 @@ -4,4 +4,4 @@ # license information. # -------------------------------------------------------------------------- -VERSION = "12.18.3" +VERSION = "12.19.0" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure/storage/blob/aio/_blob_client_async.py new/azure-storage-blob-12.19.0/azure/storage/blob/aio/_blob_client_async.py --- old/azure-storage-blob-12.18.3/azure/storage/blob/aio/_blob_client_async.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure/storage/blob/aio/_blob_client_async.py 2023-11-07 23:29:15.000000000 +0100 @@ -101,6 +101,9 @@ or 4MB. :keyword str version_id: The version id parameter is an opaque DateTime value that, when present, specifies the version of the blob to operate on. + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net. .. admonition:: Example: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure/storage/blob/aio/_blob_service_client_async.py new/azure-storage-blob-12.19.0/azure/storage/blob/aio/_blob_service_client_async.py --- old/azure-storage-blob-12.18.3/azure/storage/blob/aio/_blob_service_client_async.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure/storage/blob/aio/_blob_service_client_async.py 2023-11-07 23:29:15.000000000 +0100 @@ -33,7 +33,7 @@ from .._blob_service_client import BlobServiceClient as BlobServiceClientBase from .._deserialize import service_stats_deserialize, service_properties_deserialize from .._encryption import StorageEncryptionMixin -from .._models import ContainerProperties +from .._models import BlobProperties, ContainerProperties from .._serialize import get_api_version from ._blob_client_async import BlobClient from ._container_client_async import ContainerClient @@ -46,7 +46,6 @@ from .._shared.models import UserDelegationKey from ._lease_async import BlobLeaseClient from .._models import ( - BlobProperties, PublicAccess, BlobAnalyticsLogging, Metrics, @@ -98,6 +97,9 @@ the exceeded part will be downloaded in chunks (could be parallel). Defaults to 32*1024*1024, or 32MB. :keyword int max_chunk_get_size: The maximum chunk size used for downloading a blob. Defaults to 4*1024*1024, or 4MB. + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net. .. admonition:: Example: @@ -508,11 +510,10 @@ @distributed_trace_async async def delete_container( - self, container, # type: Union[ContainerProperties, str] - lease=None, # type: Optional[Union[BlobLeaseClient, str]] - **kwargs - ): - # type: (...) -> None + self, container: Union[ContainerProperties, str], + lease: Optional[Union["BlobLeaseClient", str]] = None, + **kwargs: Any + ) -> None: """Marks the specified container for deletion. The container and any blobs contained within it are later deleted during garbage collection. @@ -678,13 +679,12 @@ key_encryption_key=self.key_encryption_key, key_resolver_function=self.key_resolver_function) def get_blob_client( - self, container, # type: Union[ContainerProperties, str] - blob, # type: Union[BlobProperties, str] - snapshot=None, # type: Optional[Union[Dict[str, Any], str]] + self, container: Union[ContainerProperties, str], + blob: str, + snapshot: Optional[Union[Dict[str, Any], str]] = None, *, - version_id=None # type: Optional[str] - ): - # type: (...) -> BlobClient + version_id: Optional[str] = None + ) -> BlobClient: """Get a client to interact with the specified blob. The blob need not already exist. @@ -693,10 +693,8 @@ The container that the blob is in. This can either be the name of the container, or an instance of ContainerProperties. :type container: str or ~azure.storage.blob.ContainerProperties - :param blob: - The blob with which to interact. This can either be the name of the blob, - or an instance of BlobProperties. - :type blob: str or ~azure.storage.blob.BlobProperties + :param str blob: + The blob with which to interact. :param snapshot: The optional blob snapshot on which to operate. This can either be the ID of the snapshot, or a dictionary output returned by @@ -716,6 +714,12 @@ :dedent: 16 :caption: Getting the blob client to interact with a specific blob. """ + if isinstance(blob, BlobProperties): + warnings.warn( + "The use of a 'BlobProperties' instance for param blob is deprecated. " + + "Please use 'BlobProperties.name' or any other str input type instead.", + DeprecationWarning + ) try: container_name = container.name except AttributeError: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure/storage/blob/aio/_container_client_async.py new/azure-storage-blob-12.19.0/azure/storage/blob/aio/_container_client_async.py --- old/azure-storage-blob-12.18.3/azure/storage/blob/aio/_container_client_async.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure/storage/blob/aio/_container_client_async.py 2023-11-07 23:29:15.000000000 +0100 @@ -6,6 +6,7 @@ # pylint: disable=too-many-lines, invalid-overridden-method import functools +import warnings from typing import ( # pylint: disable=unused-import Any, AnyStr, AsyncIterable, AsyncIterator, Dict, List, IO, Iterable, Optional, overload, Union, TYPE_CHECKING @@ -14,7 +15,6 @@ from azure.core.async_paging import AsyncItemPaged from azure.core.exceptions import HttpResponseError, ResourceNotFoundError from azure.core.pipeline import AsyncPipeline -from azure.core.pipeline.transport import AsyncHttpResponse from azure.core.tracing.decorator import distributed_trace from azure.core.tracing.decorator_async import distributed_trace_async @@ -43,6 +43,7 @@ if TYPE_CHECKING: from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential from azure.core.credentials_async import AsyncTokenCredential + from azure.core.pipeline.transport import AsyncHttpResponse # pylint: disable=C4756 from datetime import datetime from .._models import ( # pylint: disable=unused-import AccessPolicy, @@ -94,6 +95,9 @@ the exceeded part will be downloaded in chunks (could be parallel). Defaults to 32*1024*1024, or 32MB. :keyword int max_chunk_get_size: The maximum chunk size used for downloading a blob. Defaults to 4*1024*1024, or 4MB. + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net. .. admonition:: Example: @@ -823,7 +827,7 @@ @distributed_trace_async async def upload_blob( - self, name: Union[str, BlobProperties], + self, name: str, data: Union[bytes, str, Iterable[AnyStr], AsyncIterable[AnyStr], IO[AnyStr]], blob_type: Union[str, BlobType] = BlobType.BlockBlob, length: Optional[int] = None, @@ -832,9 +836,7 @@ ) -> BlobClient: """Creates a new blob from a data source with automatic chunking. - :param name: The blob with which to interact. If specified, this value will override - a blob value specified in the blob URL. - :type name: str or ~azure.storage.blob.BlobProperties + :param str name: The blob with which to interact. :param data: The blob data to upload. :param ~azure.storage.blob.BlobType blob_type: The type of the blob. This can be either BlockBlob, PageBlob or AppendBlob. The default value is BlockBlob. @@ -946,6 +948,12 @@ :dedent: 12 :caption: Upload blob to the container. """ + if isinstance(name, BlobProperties): + warnings.warn( + "The use of a 'BlobProperties' instance for param name is deprecated. " + + "Please use 'BlobProperties.name' or any other str input type instead.", + DeprecationWarning + ) blob = self.get_blob_client(name) kwargs.setdefault('merge_span', True) timeout = kwargs.pop('timeout', None) @@ -963,11 +971,10 @@ @distributed_trace_async async def delete_blob( - self, blob, # type: Union[str, BlobProperties] - delete_snapshots=None, # type: Optional[str] - **kwargs - ): - # type: (...) -> None + self, blob: str, + delete_snapshots: Optional[str] = None, + **kwargs: Any + ) -> None: """Marks the specified blob or snapshot for deletion. The blob is later deleted during garbage collection. @@ -981,9 +988,7 @@ Soft deleted blobs or snapshots are accessible through :func:`list_blobs()` specifying `include=["deleted"]` Soft-deleted blob or snapshot can be restored using :func:`~azure.storage.blob.aio.BlobClient.undelete()` - :param blob: The blob with which to interact. If specified, this value will override - a blob value specified in the blob URL. - :type blob: str or ~azure.storage.blob.BlobProperties + :param str blob: The blob with which to interact. :param str delete_snapshots: Required if the blob has associated snapshots. Values include: - "only": Deletes only the blobs snapshots. @@ -1030,6 +1035,12 @@ #other-client--per-operation-configuration>`_. :rtype: None """ + if isinstance(blob, BlobProperties): + warnings.warn( + "The use of a 'BlobProperties' instance for param blob is deprecated. " + + "Please use 'BlobProperties.name' or any other str input type instead.", + DeprecationWarning + ) blob = self.get_blob_client(blob) # type: ignore kwargs.setdefault('merge_span', True) timeout = kwargs.pop('timeout', None) @@ -1040,39 +1051,40 @@ @overload async def download_blob( - self, blob: Union[str, BlobProperties], + self, blob: str, offset: int = None, length: int = None, *, encoding: str, - **kwargs) -> StorageStreamDownloader[str]: + **kwargs: Any + ) -> StorageStreamDownloader[str]: ... @overload async def download_blob( - self, blob: Union[str, BlobProperties], + self, blob: str, offset: int = None, length: int = None, *, encoding: None = None, - **kwargs) -> StorageStreamDownloader[bytes]: + **kwargs: Any + ) -> StorageStreamDownloader[bytes]: ... @distributed_trace_async async def download_blob( - self, blob: Union[str, BlobProperties], + self, blob: str, offset: int = None, length: int = None, *, encoding: Optional[str] = None, - **kwargs) -> StorageStreamDownloader: + **kwargs: Any + ) -> StorageStreamDownloader: """Downloads a blob to the StorageStreamDownloader. The readall() method must be used to read all the content or readinto() must be used to download the blob into a stream. Using chunks() returns an async iterator which allows the user to iterate over the content in chunks. - :param blob: The blob with which to interact. If specified, this value will override - a blob value specified in the blob URL. - :type blob: str or ~azure.storage.blob.BlobProperties + :param str blob: The blob with which to interact. :param int offset: Start of byte range to use for downloading a section of the blob. Must be set if length is provided. @@ -1149,6 +1161,12 @@ :returns: A streaming object. (StorageStreamDownloader) :rtype: ~azure.storage.blob.aio.StorageStreamDownloader """ + if isinstance(blob, BlobProperties): + warnings.warn( + "The use of a 'BlobProperties' instance for param blob is deprecated. " + + "Please use 'BlobProperties.name' or any other str input type instead.", + DeprecationWarning + ) blob_client = self.get_blob_client(blob) # type: ignore kwargs.setdefault('merge_span', True) return await blob_client.download_blob( @@ -1161,7 +1179,7 @@ async def delete_blobs( self, *blobs: Union[str, Dict[str, Any], BlobProperties], **kwargs: Any - ) -> AsyncIterator[AsyncHttpResponse]: + ) -> AsyncIterator["AsyncHttpResponse"]: """Marks the specified blobs or snapshots for deletion. The blobs are later deleted during garbage collection. @@ -1259,7 +1277,7 @@ self, standard_blob_tier: Union[str, 'StandardBlobTier'], *blobs: Union[str, Dict[str, Any], BlobProperties], **kwargs: Any - ) -> AsyncIterator[AsyncHttpResponse]: + ) -> AsyncIterator["AsyncHttpResponse"]: """This operation sets the tier on block blobs. A block blob's tier determines Hot/Cool/Archive storage type. @@ -1330,7 +1348,7 @@ self, premium_page_blob_tier: Union[str, 'PremiumPageBlobTier'], *blobs: Union[str, Dict[str, Any], BlobProperties], **kwargs: Any - ) -> AsyncIterator[AsyncHttpResponse]: + ) -> AsyncIterator["AsyncHttpResponse"]: """Sets the page blob tiers on the blobs. This API is only supported for page blobs on premium accounts. The maximum number of blobs that can be updated in a single request is 256. @@ -1379,19 +1397,17 @@ return await self._batch_send(*reqs, **options) def get_blob_client( - self, blob, # type: Union[BlobProperties, str] - snapshot=None, # type: str + self, blob: str, + snapshot: str = None, *, - version_id=None # type: Optional[str] - ): - # type: (...) -> BlobClient + version_id: Optional[str] = None + ) -> BlobClient: """Get a client to interact with the specified blob. The blob need not already exist. - :param blob: + :param str blob: The blob with which to interact. - :type blob: str or ~azure.storage.blob.BlobProperties :param str snapshot: The optional blob snapshot on which to operate. This can be the snapshot ID string or the response returned from :func:`~BlobClient.create_snapshot()`. @@ -1409,6 +1425,12 @@ :dedent: 12 :caption: Get the blob client. """ + if isinstance(blob, BlobProperties): + warnings.warn( + "The use of a 'BlobProperties' instance for param blob is deprecated. " + + "Please use 'BlobProperties.name' or any other str input type instead.", + DeprecationWarning + ) blob_name = _get_blob_name(blob) _pipeline = AsyncPipeline( transport=AsyncTransportWrapper(self._pipeline._transport), # pylint: disable = protected-access diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/azure_storage_blob.egg-info/PKG-INFO new/azure-storage-blob-12.19.0/azure_storage_blob.egg-info/PKG-INFO --- old/azure-storage-blob-12.18.3/azure_storage_blob.egg-info/PKG-INFO 2023-10-10 23:34:56.000000000 +0200 +++ new/azure-storage-blob-12.19.0/azure_storage_blob.egg-info/PKG-INFO 2023-11-07 23:30:02.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: azure-storage-blob -Version: 12.18.3 +Version: 12.19.0 Summary: Microsoft Azure Blob Storage Client Library for Python Home-page: https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-blob Author: Microsoft Corporation diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/tests/test_common_blob.py new/azure-storage-blob-12.19.0/tests/test_common_blob.py --- old/azure-storage-blob-12.18.3/tests/test_common_blob.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/tests/test_common_blob.py 2023-11-07 23:29:15.000000000 +0100 @@ -3291,4 +3291,48 @@ assert v1_blob.exists(version_id=v2_props['version_id']) is False assert blob_client.exists() is True + @BlobPreparer() + @recorded_by_proxy + def test_storage_account_audience_blob_service_client(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + self._setup(storage_account_name, storage_account_key) + self.bsc.list_containers() + + # Act + token_credential = self.generate_oauth_token() + bsc = BlobServiceClient( + self.account_url(storage_account_name, "blob"), credential=token_credential, + audience=f'https://{storage_account_name}.blob.core.windows.net' + ) + + # Assert + response = bsc.list_containers() + assert response is not None + + @BlobPreparer() + @recorded_by_proxy + def test_storage_account_audience_blob_client(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + self._setup(storage_account_name, storage_account_key) + blob_name = self._create_block_blob() + blob = self.bsc.get_blob_client(self.container_name, blob_name) + blob.exists() + + # Act + token_credential = self.generate_oauth_token() + blob = BlobClient( + self.bsc.url, container_name=self.container_name, blob_name=blob_name, + credential=token_credential, audience=f'https://{storage_account_name}.blob.core.windows.net' + ) + + # Assert + response = blob.exists() + assert response is not None + # ------------------------------------------------------------------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/tests/test_common_blob_async.py new/azure-storage-blob-12.19.0/tests/test_common_blob_async.py --- old/azure-storage-blob-12.18.3/tests/test_common_blob_async.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/tests/test_common_blob_async.py 2023-11-07 23:29:15.000000000 +0100 @@ -3216,4 +3216,48 @@ assert await v1_blob.exists(version_id=v2_props['version_id']) is False assert await blob_client.exists() is True + @BlobPreparer() + @recorded_by_proxy_async + async def test_storage_account_audience_blob_service_client(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + await self._setup(storage_account_name, storage_account_key) + self.bsc.list_containers() + + # Act + token_credential = self.generate_oauth_token() + bsc = BlobServiceClient( + self.account_url(storage_account_name, "blob"), credential=token_credential, + audience=f'https://{storage_account_name}.blob.core.windows.net' + ) + + # Assert + response = bsc.list_containers() + assert response is not None + + @BlobPreparer() + @recorded_by_proxy_async + async def test_storage_account_audience_blob_client(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + await self._setup(storage_account_name, storage_account_key) + blob_name = await self._create_block_blob() + blob = self.bsc.get_blob_client(self.container_name, blob_name) + await blob.exists() + + # Act + token_credential = self.generate_oauth_token() + blob = BlobClient( + self.bsc.url, container_name=self.container_name, blob_name=blob_name, + credential=token_credential, audience=f'https://{storage_account_name}.blob.core.windows.net' + ) + + # Assert + response = await blob.exists() + assert response is not None + # ------------------------------------------------------------------------------ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/tests/test_container.py new/azure-storage-blob-12.19.0/tests/test_container.py --- old/azure-storage-blob-12.18.3/tests/test_container.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/tests/test_container.py 2023-11-07 23:29:15.000000000 +0100 @@ -2697,3 +2697,24 @@ assert items_on_page1[1] == 'blob2' assert len(items_on_page2) == 1 assert items_on_page2[0] == 'blob3' + + @BlobPreparer() + @recorded_by_proxy + def test_storage_account_audience_container_client(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + cc = ContainerClient(self.account_url(storage_account_name, "blob"), 'testcont', storage_account_key) + cc.exists() + + # Act + token_credential = self.generate_oauth_token() + cc = ContainerClient( + self.account_url(storage_account_name, "blob"), 'testcont', credential=token_credential, + audience=f'https://{storage_account_name}.blob.core.windows.net' + ) + + # Assert + response = cc.exists() + assert response is not None diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure-storage-blob-12.18.3/tests/test_container_async.py new/azure-storage-blob-12.19.0/tests/test_container_async.py --- old/azure-storage-blob-12.18.3/tests/test_container_async.py 2023-10-10 23:34:03.000000000 +0200 +++ new/azure-storage-blob-12.19.0/tests/test_container_async.py 2023-11-07 23:29:15.000000000 +0100 @@ -2567,3 +2567,24 @@ assert props2['version_id'] == v2_props['version_id'] assert props3['version_id'] == v3_props['version_id'] assert props4['version_id'] == v4_props['version_id'] + + @BlobPreparer() + @recorded_by_proxy_async + async def test_storage_account_audience_container_client(self, **kwargs): + storage_account_name = kwargs.pop("storage_account_name") + storage_account_key = kwargs.pop("storage_account_key") + + # Arrange + cc = ContainerClient(self.account_url(storage_account_name, "blob"), 'testcont', storage_account_key) + await cc.exists() + + # Act + token_credential = self.generate_oauth_token() + cc = ContainerClient( + self.account_url(storage_account_name, "blob"), 'testcont', credential=token_credential, + audience=f'https://{storage_account_name}.blob.core.windows.net' + ) + + # Assert + response = await cc.exists() + assert response is not None