1# pylint: disable=too-many-lines
2# -------------------------------------------------------------------------
3# Copyright (c) Microsoft Corporation. All rights reserved.
4# Licensed under the MIT License. See License.txt in the project root for
5# license information.
6# --------------------------------------------------------------------------
7
8import functools
9from typing import (  # pylint: disable=unused-import
10    Union, Optional, Any, Iterable, AnyStr, Dict, List, Tuple, IO, AsyncIterator,
11    TYPE_CHECKING
12)
13
14from azure.core.tracing.decorator import distributed_trace
15from azure.core.tracing.decorator_async import distributed_trace_async
16from azure.core.async_paging import AsyncItemPaged
17from azure.core.pipeline import AsyncPipeline
18from azure.core.pipeline.transport import HttpRequest, AsyncHttpResponse
19
20from .._shared.base_client_async import AsyncStorageAccountHostsMixin, AsyncTransportWrapper
21from .._shared.policies_async import ExponentialRetry
22from .._shared.request_handlers import add_metadata_headers, serialize_iso
23from .._shared.response_handlers import (
24    process_storage_error,
25    return_response_headers,
26    return_headers_and_deserialized)
27from .._generated.aio import AzureBlobStorage
28from .._generated.models import (
29    StorageErrorException,
30    SignedIdentifier)
31from .._deserialize import deserialize_container_properties
32from .._serialize import get_modify_conditions
33from .._container_client import ContainerClient as ContainerClientBase, _get_blob_name
34from .._lease import get_access_conditions
35from .._models import ContainerProperties, BlobProperties, BlobType  # pylint: disable=unused-import
36from ._models import BlobPropertiesPaged, BlobPrefix
37from ._lease_async import BlobLeaseClient
38from ._blob_client_async import BlobClient
39
40if TYPE_CHECKING:
41    from azure.core.pipeline.transport import HttpTransport
42    from azure.core.pipeline.policies import HTTPPolicy
43    from .._models import ContainerSasPermissions, PublicAccess
44    from datetime import datetime
45    from .._models import ( # pylint: disable=unused-import
46        AccessPolicy,
47        ContentSettings,
48        StandardBlobTier,
49        PremiumPageBlobTier)
50
51
52class ContainerClient(AsyncStorageAccountHostsMixin, ContainerClientBase):
53    """A client to interact with a specific container, although that container
54    may not yet exist.
55
56    For operations relating to a specific blob within this container, a blob client can be
57    retrieved using the :func:`~get_blob_client` function.
58
59    :param str account_url:
60        The URI to the storage account. In order to create a client given the full URI to the container,
61        use the :func:`from_container_url` classmethod.
62    :param container_name:
63        The name of the container for the blob.
64    :type container_name: str
65    :param credential:
66        The credentials with which to authenticate. This is optional if the
67        account URL already has a SAS token. The value can be a SAS token string, an account
68        shared access key, or an instance of a TokenCredentials class from azure.identity.
69        If the URL already has a SAS token, specifying an explicit credential will take priority.
70    :keyword str secondary_hostname:
71        The hostname of the secondary endpoint.
72    :keyword int max_block_size: The maximum chunk size for uploading a block blob in chunks.
73        Defaults to 4*1024*1024, or 4MB.
74    :keyword int max_single_put_size: If the blob size is less than max_single_put_size, then the blob will be
75        uploaded with only one http PUT request. If the blob size is larger than max_single_put_size,
76        the blob will be uploaded in chunks. Defaults to 64*1024*1024, or 64MB.
77    :keyword int min_large_block_upload_threshold: The minimum chunk size required to use the memory efficient
78        algorithm when uploading a block blob. Defaults to 4*1024*1024+1.
79    :keyword bool use_byte_buffer: Use a byte buffer for block blob uploads. Defaults to False.
80    :keyword int max_page_size: The maximum chunk size for uploading a page blob. Defaults to 4*1024*1024, or 4MB.
81    :keyword int max_single_get_size: The maximum size for a blob to be downloaded in a single call,
82        the exceeded part will be downloaded in chunks (could be parallel). Defaults to 32*1024*1024, or 32MB.
83    :keyword int max_chunk_get_size: The maximum chunk size used for downloading a blob. Defaults to 4*1024*1024,
84        or 4MB.
85
86    .. admonition:: Example:
87
88        .. literalinclude:: ../samples/blob_samples_containers_async.py
89            :start-after: [START create_container_client_from_service]
90            :end-before: [END create_container_client_from_service]
91            :language: python
92            :dedent: 8
93            :caption: Get a ContainerClient from an existing BlobServiceClient.
94
95        .. literalinclude:: ../samples/blob_samples_containers_async.py
96            :start-after: [START create_container_client_sasurl]
97            :end-before: [END create_container_client_sasurl]
98            :language: python
99            :dedent: 12
100            :caption: Creating the container client directly.
101    """
102    def __init__(
103            self, account_url,  # type: str
104            container_name,  # type: str
105            credential=None,  # type: Optional[Any]
106            **kwargs  # type: Any
107        ):
108        # type: (...) -> None
109        kwargs['retry_policy'] = kwargs.get('retry_policy') or ExponentialRetry(**kwargs)
110        super(ContainerClient, self).__init__(
111            account_url,
112            container_name=container_name,
113            credential=credential,
114            **kwargs)
115        self._client = AzureBlobStorage(url=self.url, pipeline=self._pipeline)
116        self._loop = kwargs.get('loop', None)
117
118    @distributed_trace_async
119    async def create_container(self, metadata=None, public_access=None, **kwargs):
120        # type: (Optional[Dict[str, str]], Optional[Union[PublicAccess, str]], **Any) -> None
121        """
122        Creates a new container under the specified account. If the container
123        with the same name already exists, the operation fails.
124
125        :param metadata:
126            A dict with name_value pairs to associate with the
127            container as metadata. Example:{'Category':'test'}
128        :type metadata: dict[str, str]
129        :param ~azure.storage.blob.PublicAccess public_access:
130            Possible values include: 'container', 'blob'.
131        :keyword int timeout:
132            The timeout parameter is expressed in seconds.
133        :rtype: None
134
135        .. admonition:: Example:
136
137            .. literalinclude:: ../samples/blob_samples_containers_async.py
138                :start-after: [START create_container]
139                :end-before: [END create_container]
140                :language: python
141                :dedent: 16
142                :caption: Creating a container to store blobs.
143        """
144        headers = kwargs.pop('headers', {})
145        headers.update(add_metadata_headers(metadata)) # type: ignore
146        timeout = kwargs.pop('timeout', None)
147        try:
148            return await self._client.container.create( # type: ignore
149                timeout=timeout,
150                access=public_access,
151                cls=return_response_headers,
152                headers=headers,
153                **kwargs)
154        except StorageErrorException as error:
155            process_storage_error(error)
156
157    @distributed_trace_async
158    async def delete_container(
159            self, **kwargs):
160        # type: (Any) -> None
161        """
162        Marks the specified container for deletion. The container and any blobs
163        contained within it are later deleted during garbage collection.
164
165        :keyword lease:
166            If specified, delete_container only succeeds if the
167            container's lease is active and matches this ID.
168            Required if the container has an active lease.
169        :paramtype lease: ~azure.storage.blob.aio.BlobLeaseClient or str
170        :keyword ~datetime.datetime if_modified_since:
171            A DateTime value. Azure expects the date value passed in to be UTC.
172            If timezone is included, any non-UTC datetimes will be converted to UTC.
173            If a date is passed in without timezone info, it is assumed to be UTC.
174            Specify this header to perform the operation only
175            if the resource has been modified since the specified time.
176        :keyword ~datetime.datetime if_unmodified_since:
177            A DateTime value. Azure expects the date value passed in to be UTC.
178            If timezone is included, any non-UTC datetimes will be converted to UTC.
179            If a date is passed in without timezone info, it is assumed to be UTC.
180            Specify this header to perform the operation only if
181            the resource has not been modified since the specified date/time.
182        :keyword str etag:
183            An ETag value, or the wildcard character (*). Used to check if the resource has changed,
184            and act according to the condition specified by the `match_condition` parameter.
185        :keyword ~azure.core.MatchConditions match_condition:
186            The match condition to use upon the etag.
187        :keyword int timeout:
188            The timeout parameter is expressed in seconds.
189        :rtype: None
190
191        .. admonition:: Example:
192
193            .. literalinclude:: ../samples/blob_samples_containers_async.py
194                :start-after: [START delete_container]
195                :end-before: [END delete_container]
196                :language: python
197                :dedent: 16
198                :caption: Delete a container.
199        """
200        lease = kwargs.pop('lease', None)
201        access_conditions = get_access_conditions(lease)
202        mod_conditions = get_modify_conditions(kwargs)
203        timeout = kwargs.pop('timeout', None)
204        try:
205            await self._client.container.delete(
206                timeout=timeout,
207                lease_access_conditions=access_conditions,
208                modified_access_conditions=mod_conditions,
209                **kwargs)
210        except StorageErrorException as error:
211            process_storage_error(error)
212
213    @distributed_trace_async
214    async def acquire_lease(
215            self, lease_duration=-1,  # type: int
216            lease_id=None,  # type: Optional[str]
217            **kwargs):
218        # type: (...) -> BlobLeaseClient
219        """
220        Requests a new lease. If the container does not have an active lease,
221        the Blob service creates a lease on the container and returns a new
222        lease ID.
223
224        :param int lease_duration:
225            Specifies the duration of the lease, in seconds, or negative one
226            (-1) for a lease that never expires. A non-infinite lease can be
227            between 15 and 60 seconds. A lease duration cannot be changed
228            using renew or change. Default is -1 (infinite lease).
229        :param str lease_id:
230            Proposed lease ID, in a GUID string format. The Blob service returns
231            400 (Invalid request) if the proposed lease ID is not in the correct format.
232        :keyword ~datetime.datetime if_modified_since:
233            A DateTime value. Azure expects the date value passed in to be UTC.
234            If timezone is included, any non-UTC datetimes will be converted to UTC.
235            If a date is passed in without timezone info, it is assumed to be UTC.
236            Specify this header to perform the operation only
237            if the resource has been modified since the specified time.
238        :keyword ~datetime.datetime if_unmodified_since:
239            A DateTime value. Azure expects the date value passed in to be UTC.
240            If timezone is included, any non-UTC datetimes will be converted to UTC.
241            If a date is passed in without timezone info, it is assumed to be UTC.
242            Specify this header to perform the operation only if
243            the resource has not been modified since the specified date/time.
244        :keyword str etag:
245            An ETag value, or the wildcard character (*). Used to check if the resource has changed,
246            and act according to the condition specified by the `match_condition` parameter.
247        :keyword ~azure.core.MatchConditions match_condition:
248            The match condition to use upon the etag.
249        :keyword int timeout:
250            The timeout parameter is expressed in seconds.
251        :returns: A BlobLeaseClient object, that can be run in a context manager.
252        :rtype: ~azure.storage.blob.aio.BlobLeaseClient
253
254        .. admonition:: Example:
255
256            .. literalinclude:: ../samples/blob_samples_containers_async.py
257                :start-after: [START acquire_lease_on_container]
258                :end-before: [END acquire_lease_on_container]
259                :language: python
260                :dedent: 12
261                :caption: Acquiring a lease on the container.
262        """
263        lease = BlobLeaseClient(self, lease_id=lease_id) # type: ignore
264        kwargs.setdefault('merge_span', True)
265        timeout = kwargs.pop('timeout', None)
266        await lease.acquire(lease_duration=lease_duration, timeout=timeout, **kwargs)
267        return lease
268
269    @distributed_trace_async
270    async def get_account_information(self, **kwargs):
271        # type: (**Any) -> Dict[str, str]
272        """Gets information related to the storage account.
273
274        The information can also be retrieved if the user has a SAS to a container or blob.
275        The keys in the returned dictionary include 'sku_name' and 'account_kind'.
276
277        :returns: A dict of account information (SKU and account type).
278        :rtype: dict(str, str)
279        """
280        try:
281            return await self._client.container.get_account_info(cls=return_response_headers, **kwargs) # type: ignore
282        except StorageErrorException as error:
283            process_storage_error(error)
284
285    @distributed_trace_async
286    async def get_container_properties(self, **kwargs):
287        # type: (**Any) -> ContainerProperties
288        """Returns all user-defined metadata and system properties for the specified
289        container. The data returned does not include the container's list of blobs.
290
291        :keyword lease:
292            If specified, get_container_properties only succeeds if the
293            container's lease is active and matches this ID.
294        :paramtype lease: ~azure.storage.blob.aio.BlobLeaseClient or str
295        :keyword int timeout:
296            The timeout parameter is expressed in seconds.
297        :return: Properties for the specified container within a container object.
298        :rtype: ~azure.storage.blob.ContainerProperties
299
300        .. admonition:: Example:
301
302            .. literalinclude:: ../samples/blob_samples_containers_async.py
303                :start-after: [START get_container_properties]
304                :end-before: [END get_container_properties]
305                :language: python
306                :dedent: 16
307                :caption: Getting properties on the container.
308        """
309        lease = kwargs.pop('lease', None)
310        access_conditions = get_access_conditions(lease)
311        timeout = kwargs.pop('timeout', None)
312        try:
313            response = await self._client.container.get_properties(
314                timeout=timeout,
315                lease_access_conditions=access_conditions,
316                cls=deserialize_container_properties,
317                **kwargs)
318        except StorageErrorException as error:
319            process_storage_error(error)
320        response.name = self.container_name
321        return response # type: ignore
322
323    @distributed_trace_async
324    async def set_container_metadata( # type: ignore
325            self, metadata=None,  # type: Optional[Dict[str, str]]
326            **kwargs
327        ):
328        # type: (...) -> Dict[str, Union[str, datetime]]
329        """Sets one or more user-defined name-value pairs for the specified
330        container. Each call to this operation replaces all existing metadata
331        attached to the container. To remove all metadata from the container,
332        call this operation with no metadata dict.
333
334        :param metadata:
335            A dict containing name-value pairs to associate with the container as
336            metadata. Example: {'category':'test'}
337        :type metadata: dict[str, str]
338        :keyword lease:
339            If specified, set_container_metadata only succeeds if the
340            container's lease is active and matches this ID.
341        :paramtype lease: ~azure.storage.blob.aio.BlobLeaseClient or str
342        :keyword ~datetime.datetime if_modified_since:
343            A DateTime value. Azure expects the date value passed in to be UTC.
344            If timezone is included, any non-UTC datetimes will be converted to UTC.
345            If a date is passed in without timezone info, it is assumed to be UTC.
346            Specify this header to perform the operation only
347            if the resource has been modified since the specified time.
348        :keyword int timeout:
349            The timeout parameter is expressed in seconds.
350        :returns: Container-updated property dict (Etag and last modified).
351
352        .. admonition:: Example:
353
354            .. literalinclude:: ../samples/blob_samples_containers_async.py
355                :start-after: [START set_container_metadata]
356                :end-before: [END set_container_metadata]
357                :language: python
358                :dedent: 16
359                :caption: Setting metadata on the container.
360        """
361        headers = kwargs.pop('headers', {})
362        headers.update(add_metadata_headers(metadata))
363        lease = kwargs.pop('lease', None)
364        access_conditions = get_access_conditions(lease)
365        mod_conditions = get_modify_conditions(kwargs)
366        timeout = kwargs.pop('timeout', None)
367        try:
368            return await self._client.container.set_metadata( # type: ignore
369                timeout=timeout,
370                lease_access_conditions=access_conditions,
371                modified_access_conditions=mod_conditions,
372                cls=return_response_headers,
373                headers=headers,
374                **kwargs)
375        except StorageErrorException as error:
376            process_storage_error(error)
377
378    @distributed_trace_async
379    async def get_container_access_policy(self, **kwargs):
380        # type: (Any) -> Dict[str, Any]
381        """Gets the permissions for the specified container.
382        The permissions indicate whether container data may be accessed publicly.
383
384        :keyword lease:
385            If specified, get_container_access_policy only succeeds if the
386            container's lease is active and matches this ID.
387        :paramtype lease: ~azure.storage.blob.aio.BlobLeaseClient or str
388        :keyword int timeout:
389            The timeout parameter is expressed in seconds.
390        :returns: Access policy information in a dict.
391        :rtype: dict[str, Any]
392
393        .. admonition:: Example:
394
395            .. literalinclude:: ../samples/blob_samples_containers_async.py
396                :start-after: [START get_container_access_policy]
397                :end-before: [END get_container_access_policy]
398                :language: python
399                :dedent: 16
400                :caption: Getting the access policy on the container.
401        """
402        lease = kwargs.pop('lease', None)
403        access_conditions = get_access_conditions(lease)
404        timeout = kwargs.pop('timeout', None)
405        try:
406            response, identifiers = await self._client.container.get_access_policy(
407                timeout=timeout,
408                lease_access_conditions=access_conditions,
409                cls=return_headers_and_deserialized,
410                **kwargs)
411        except StorageErrorException as error:
412            process_storage_error(error)
413        return {
414            'public_access': response.get('blob_public_access'),
415            'signed_identifiers': identifiers or []
416        }
417
418    @distributed_trace_async
419    async def set_container_access_policy(
420            self, signed_identifiers,  # type: Dict[str, AccessPolicy]
421            public_access=None,  # type: Optional[Union[str, PublicAccess]]
422            **kwargs  # type: Any
423        ):  # type: (...) -> Dict[str, Union[str, datetime]]
424        """Sets the permissions for the specified container or stored access
425        policies that may be used with Shared Access Signatures. The permissions
426        indicate whether blobs in a container may be accessed publicly.
427
428        :param signed_identifiers:
429            A dictionary of access policies to associate with the container. The
430            dictionary may contain up to 5 elements. An empty dictionary
431            will clear the access policies set on the service.
432        :type signed_identifiers: dict[str, ~azure.storage.blob.AccessPolicy]
433        :param ~azure.storage.blob.PublicAccess public_access:
434            Possible values include: 'container', 'blob'.
435        :keyword lease:
436            Required if the container has an active lease. Value can be a BlobLeaseClient object
437            or the lease ID as a string.
438        :paramtype lease: ~azure.storage.blob.aio.BlobLeaseClient or str
439        :keyword ~datetime.datetime if_modified_since:
440            A datetime value. Azure expects the date value passed in to be UTC.
441            If timezone is included, any non-UTC datetimes will be converted to UTC.
442            If a date is passed in without timezone info, it is assumed to be UTC.
443            Specify this header to perform the operation only
444            if the resource has been modified since the specified date/time.
445        :keyword ~datetime.datetime if_unmodified_since:
446            A datetime value. Azure expects the date value passed in to be UTC.
447            If timezone is included, any non-UTC datetimes will be converted to UTC.
448            If a date is passed in without timezone info, it is assumed to be UTC.
449            Specify this header to perform the operation only if
450            the resource has not been modified since the specified date/time.
451        :keyword int timeout:
452            The timeout parameter is expressed in seconds.
453        :returns: Container-updated property dict (Etag and last modified).
454        :rtype: dict[str, str or ~datetime.datetime]
455
456        .. admonition:: Example:
457
458            .. literalinclude:: ../samples/blob_samples_containers_async.py
459                :start-after: [START set_container_access_policy]
460                :end-before: [END set_container_access_policy]
461                :language: python
462                :dedent: 16
463                :caption: Setting access policy on the container.
464        """
465        timeout = kwargs.pop('timeout', None)
466        lease = kwargs.pop('lease', None)
467        if len(signed_identifiers) > 5:
468            raise ValueError(
469                'Too many access policies provided. The server does not support setting '
470                'more than 5 access policies on a single resource.')
471        identifiers = []
472        for key, value in signed_identifiers.items():
473            if value:
474                value.start = serialize_iso(value.start)
475                value.expiry = serialize_iso(value.expiry)
476            identifiers.append(SignedIdentifier(id=key, access_policy=value)) # type: ignore
477        signed_identifiers = identifiers # type: ignore
478
479        mod_conditions = get_modify_conditions(kwargs)
480        access_conditions = get_access_conditions(lease)
481        try:
482            return await self._client.container.set_access_policy(
483                container_acl=signed_identifiers or None,
484                timeout=timeout,
485                access=public_access,
486                lease_access_conditions=access_conditions,
487                modified_access_conditions=mod_conditions,
488                cls=return_response_headers,
489                **kwargs)
490        except StorageErrorException as error:
491            process_storage_error(error)
492
493    @distributed_trace
494    def list_blobs(self, name_starts_with=None, include=None, **kwargs):
495        # type: (Optional[str], Optional[Any], **Any) -> AsyncItemPaged[BlobProperties]
496        """Returns a generator to list the blobs under the specified container.
497        The generator will lazily follow the continuation tokens returned by
498        the service.
499
500        :param str name_starts_with:
501            Filters the results to return only blobs whose names
502            begin with the specified prefix.
503        :param list[str] include:
504            Specifies one or more additional datasets to include in the response.
505            Options include: 'snapshots', 'metadata', 'uncommittedblobs', 'copy', 'deleted'.
506        :keyword int timeout:
507            The timeout parameter is expressed in seconds.
508        :returns: An iterable (auto-paging) response of BlobProperties.
509        :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.storage.blob.BlobProperties]
510
511        .. admonition:: Example:
512
513            .. literalinclude:: ../samples/blob_samples_containers_async.py
514                :start-after: [START list_blobs_in_container]
515                :end-before: [END list_blobs_in_container]
516                :language: python
517                :dedent: 12
518                :caption: List the blobs in the container.
519        """
520        if include and not isinstance(include, list):
521            include = [include]
522
523        results_per_page = kwargs.pop('results_per_page', None)
524        timeout = kwargs.pop('timeout', None)
525        command = functools.partial(
526            self._client.container.list_blob_flat_segment,
527            include=include,
528            timeout=timeout,
529            **kwargs)
530        return AsyncItemPaged(
531            command,
532            prefix=name_starts_with,
533            results_per_page=results_per_page,
534            page_iterator_class=BlobPropertiesPaged
535        )
536
537    @distributed_trace
538    def walk_blobs(
539            self, name_starts_with=None, # type: Optional[str]
540            include=None, # type: Optional[Any]
541            delimiter="/", # type: str
542            **kwargs # type: Optional[Any]
543        ):
544        # type: (...) -> AsyncItemPaged[BlobProperties]
545        """Returns a generator to list the blobs under the specified container.
546        The generator will lazily follow the continuation tokens returned by
547        the service. This operation will list blobs in accordance with a hierarchy,
548        as delimited by the specified delimiter character.
549
550        :param str name_starts_with:
551            Filters the results to return only blobs whose names
552            begin with the specified prefix.
553        :param list[str] include:
554            Specifies one or more additional datasets to include in the response.
555            Options include: 'snapshots', 'metadata', 'uncommittedblobs', 'copy', 'deleted'.
556        :param str delimiter:
557            When the request includes this parameter, the operation returns a BlobPrefix
558            element in the response body that acts as a placeholder for all blobs whose
559            names begin with the same substring up to the appearance of the delimiter
560            character. The delimiter may be a single character or a string.
561        :keyword int timeout:
562            The timeout parameter is expressed in seconds.
563        :returns: An iterable (auto-paging) response of BlobProperties.
564        :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.storage.blob.BlobProperties]
565        """
566        if include and not isinstance(include, list):
567            include = [include]
568
569        results_per_page = kwargs.pop('results_per_page', None)
570        timeout = kwargs.pop('timeout', None)
571        command = functools.partial(
572            self._client.container.list_blob_hierarchy_segment,
573            delimiter=delimiter,
574            include=include,
575            timeout=timeout,
576            **kwargs)
577        return BlobPrefix(
578            command,
579            prefix=name_starts_with,
580            results_per_page=results_per_page,
581            delimiter=delimiter)
582
583    @distributed_trace_async
584    async def upload_blob(
585            self, name,  # type: Union[str, BlobProperties]
586            data,  # type: Union[Iterable[AnyStr], IO[AnyStr]]
587            blob_type=BlobType.BlockBlob,  # type: Union[str, BlobType]
588            length=None,  # type: Optional[int]
589            metadata=None,  # type: Optional[Dict[str, str]]
590            **kwargs
591        ):
592        # type: (...) -> BlobClient
593        """Creates a new blob from a data source with automatic chunking.
594
595        :param name: The blob with which to interact. If specified, this value will override
596            a blob value specified in the blob URL.
597        :type name: str or ~azure.storage.blob.BlobProperties
598        :param data: The blob data to upload.
599        :param ~azure.storage.blob.BlobType blob_type: The type of the blob. This can be
600            either BlockBlob, PageBlob or AppendBlob. The default value is BlockBlob.
601        :param int length:
602            Number of bytes to read from the stream. This is optional, but
603            should be supplied for optimal performance.
604        :param metadata:
605            Name-value pairs associated with the blob as metadata.
606        :type metadata: dict(str, str)
607        :keyword bool overwrite: Whether the blob to be uploaded should overwrite the current data.
608            If True, upload_blob will overwrite the existing data. If set to False, the
609            operation will fail with ResourceExistsError. The exception to the above is with Append
610            blob types: if set to False and the data already exists, an error will not be raised
611            and the data will be appended to the existing blob. If set overwrite=True, then the existing
612            append blob will be deleted, and a new one created. Defaults to False.
613        :keyword ~azure.storage.blob.ContentSettings content_settings:
614            ContentSettings object used to set blob properties. Used to set content type, encoding,
615            language, disposition, md5, and cache control.
616        :keyword bool validate_content:
617            If true, calculates an MD5 hash for each chunk of the blob. The storage
618            service checks the hash of the content that has arrived with the hash
619            that was sent. This is primarily valuable for detecting bitflips on
620            the wire if using http instead of https, as https (the default), will
621            already validate. Note that this MD5 hash is not stored with the
622            blob. Also note that if enabled, the memory-efficient upload algorithm
623            will not be used, because computing the MD5 hash requires buffering
624            entire blocks, and doing so defeats the purpose of the memory-efficient algorithm.
625        :keyword lease:
626            Required if the container has an active lease. Value can be a BlobLeaseClient object
627            or the lease ID as a string.
628        :paramtype lease: ~azure.storage.blob.aio.BlobLeaseClient or str
629        :keyword ~datetime.datetime if_modified_since:
630            A DateTime value. Azure expects the date value passed in to be UTC.
631            If timezone is included, any non-UTC datetimes will be converted to UTC.
632            If a date is passed in without timezone info, it is assumed to be UTC.
633            Specify this header to perform the operation only
634            if the resource has been modified since the specified time.
635        :keyword ~datetime.datetime if_unmodified_since:
636            A DateTime value. Azure expects the date value passed in to be UTC.
637            If timezone is included, any non-UTC datetimes will be converted to UTC.
638            If a date is passed in without timezone info, it is assumed to be UTC.
639            Specify this header to perform the operation only if
640            the resource has not been modified since the specified date/time.
641        :keyword str etag:
642            An ETag value, or the wildcard character (*). Used to check if the resource has changed,
643            and act according to the condition specified by the `match_condition` parameter.
644        :keyword ~azure.core.MatchConditions match_condition:
645            The match condition to use upon the etag.
646        :keyword int timeout:
647            The timeout parameter is expressed in seconds. This method may make
648            multiple calls to the Azure service and the timeout will apply to
649            each call individually.
650        :keyword ~azure.storage.blob.PremiumPageBlobTier premium_page_blob_tier:
651            A page blob tier value to set the blob to. The tier correlates to the size of the
652            blob and number of allowed IOPS. This is only applicable to page blobs on
653            premium storage accounts.
654        :keyword ~azure.storage.blob.StandardBlobTier standard_blob_tier:
655            A standard blob tier value to set the blob to. For this version of the library,
656            this is only applicable to block blobs on standard storage accounts.
657        :keyword int maxsize_condition:
658            Optional conditional header. The max length in bytes permitted for
659            the append blob. If the Append Block operation would cause the blob
660            to exceed that limit or if the blob size is already greater than the
661            value specified in this header, the request will fail with
662            MaxBlobSizeConditionNotMet error (HTTP status code 412 - Precondition Failed).
663        :keyword int max_concurrency:
664            Maximum number of parallel connections to use when the blob size exceeds
665            64MB.
666        :keyword ~azure.storage.blob.CustomerProvidedEncryptionKey cpk:
667            Encrypts the data on the service-side with the given key.
668            Use of customer-provided keys must be done over HTTPS.
669            As the encryption key itself is provided in the request,
670            a secure connection must be established to transfer the key.
671        :keyword str encoding:
672            Defaults to UTF-8.
673        :returns: A BlobClient to interact with the newly uploaded blob.
674        :rtype: ~azure.storage.blob.aio.BlobClient
675
676        .. admonition:: Example:
677
678            .. literalinclude:: ../samples/blob_samples_containers_async.py
679                :start-after: [START upload_blob_to_container]
680                :end-before: [END upload_blob_to_container]
681                :language: python
682                :dedent: 12
683                :caption: Upload blob to the container.
684        """
685        blob = self.get_blob_client(name)
686        kwargs.setdefault('merge_span', True)
687        timeout = kwargs.pop('timeout', None)
688        encoding = kwargs.pop('encoding', 'UTF-8')
689        await blob.upload_blob(
690            data,
691            blob_type=blob_type,
692            length=length,
693            metadata=metadata,
694            timeout=timeout,
695            encoding=encoding,
696            **kwargs
697        )
698        return blob
699
700    @distributed_trace_async
701    async def delete_blob(
702            self, blob,  # type: Union[str, BlobProperties]
703            delete_snapshots=None,  # type: Optional[str]
704            **kwargs
705        ):
706        # type: (...) -> None
707        """Marks the specified blob or snapshot for deletion.
708
709        The blob is later deleted during garbage collection.
710        Note that in order to delete a blob, you must delete all of its
711        snapshots. You can delete both at the same time with the delete_blob
712        operation.
713
714        If a delete retention policy is enabled for the service, then this operation soft deletes the blob or snapshot
715        and retains the blob or snapshot for specified number of days.
716        After specified number of days, blob's data is removed from the service during garbage collection.
717        Soft deleted blob or snapshot is accessible through :func:`list_blobs()` specifying `include=["deleted"]`
718        option. Soft-deleted blob or snapshot can be restored using :func:`~BlobClient.undelete()`
719
720        :param blob: The blob with which to interact. If specified, this value will override
721            a blob value specified in the blob URL.
722        :type blob: str or ~azure.storage.blob.BlobProperties
723        :param str delete_snapshots:
724            Required if the blob has associated snapshots. Values include:
725             - "only": Deletes only the blobs snapshots.
726             - "include": Deletes the blob along with all snapshots.
727        :keyword lease:
728            Required if the blob has an active lease. Value can be a Lease object
729            or the lease ID as a string.
730        :paramtype lease: ~azure.storage.blob.aio.BlobLeaseClient or str
731        :keyword ~datetime.datetime if_modified_since:
732            A DateTime value. Azure expects the date value passed in to be UTC.
733            If timezone is included, any non-UTC datetimes will be converted to UTC.
734            If a date is passed in without timezone info, it is assumed to be UTC.
735            Specify this header to perform the operation only
736            if the resource has been modified since the specified time.
737        :keyword ~datetime.datetime if_unmodified_since:
738            A DateTime value. Azure expects the date value passed in to be UTC.
739            If timezone is included, any non-UTC datetimes will be converted to UTC.
740            If a date is passed in without timezone info, it is assumed to be UTC.
741            Specify this header to perform the operation only if
742            the resource has not been modified since the specified date/time.
743        :keyword str etag:
744            An ETag value, or the wildcard character (*). Used to check if the resource has changed,
745            and act according to the condition specified by the `match_condition` parameter.
746        :keyword ~azure.core.MatchConditions match_condition:
747            The match condition to use upon the etag.
748        :keyword int timeout:
749            The timeout parameter is expressed in seconds.
750        :rtype: None
751        """
752        blob = self.get_blob_client(blob) # type: ignore
753        kwargs.setdefault('merge_span', True)
754        timeout = kwargs.pop('timeout', None)
755        await blob.delete_blob( # type: ignore
756            delete_snapshots=delete_snapshots,
757            timeout=timeout,
758            **kwargs)
759
760    @distributed_trace_async
761    async def delete_blobs(  # pylint: disable=arguments-differ
762            self, *blobs: Union[str, BlobProperties],
763            delete_snapshots: Optional[str] = None,
764            lease: Optional[Union[str, BlobLeaseClient]] = None,
765            **kwargs
766        ) -> AsyncIterator[AsyncHttpResponse]:
767        """Marks the specified blobs or snapshots for deletion.
768
769        The blobs are later deleted during garbage collection.
770        Note that in order to delete blobs, you must delete all of their
771        snapshots. You can delete both at the same time with the delete_blobs operation.
772
773        If a delete retention policy is enabled for the service, then this operation soft deletes the blobs or snapshots
774        and retains the blobs or snapshots for specified number of days.
775        After specified number of days, blobs' data is removed from the service during garbage collection.
776        Soft deleted blobs or snapshots are accessible through :func:`list_blobs()` specifying `include=["deleted"]`
777        Soft-deleted blobs or snapshots can be restored using :func:`~BlobClient.undelete()`
778
779        :param blobs: The blob names with which to interact. This can be a single blob, or multiple values can
780            be supplied, where each value is either the name of the blob (str) or BlobProperties.
781        :type blobs: str or ~azure.storage.blob.BlobProperties
782        :param str delete_snapshots:
783            Required if a blob has associated snapshots. Values include:
784             - "only": Deletes only the blobs snapshots.
785             - "include": Deletes the blob along with all snapshots.
786        :param lease:
787            Required if a blob has an active lease. Value can be a BlobLeaseClient object
788            or the lease ID as a string.
789        :type lease: ~azure.storage.blob.aio.BlobLeaseClient or str
790        :keyword ~datetime.datetime if_modified_since:
791            A DateTime value. Azure expects the date value passed in to be UTC.
792            If timezone is included, any non-UTC datetimes will be converted to UTC.
793            If a date is passed in without timezone info, it is assumed to be UTC.
794            Specify this header to perform the operation only
795            if the resource has been modified since the specified time.
796        :keyword ~datetime.datetime if_unmodified_since:
797            A DateTime value. Azure expects the date value passed in to be UTC.
798            If timezone is included, any non-UTC datetimes will be converted to UTC.
799            If a date is passed in without timezone info, it is assumed to be UTC.
800            Specify this header to perform the operation only if
801            the resource has not been modified since the specified date/time.
802        :keyword bool raise_on_any_failure:
803            This is a boolean param which defaults to True. When this is set, an exception
804            is raised even if there is a single operation failure. For optimal performance,
805            this should be set to False
806        :keyword str etag:
807            An ETag value, or the wildcard character (*). Used to check if the resource has changed,
808            and act according to the condition specified by the `match_condition` parameter.
809        :keyword ~azure.core.MatchConditions match_condition:
810            The match condition to use upon the etag.
811        :keyword int timeout:
812            The timeout parameter is expressed in seconds.
813        :return: An async iterator of responses, one for each blob in order
814        :rtype: asynciterator[~azure.core.pipeline.transport.AsyncHttpResponse]
815
816        .. admonition:: Example:
817
818            .. literalinclude:: ../samples/blob_samples_common_async.py
819                :start-after: [START delete_multiple_blobs]
820                :end-before: [END delete_multiple_blobs]
821                :language: python
822                :dedent: 12
823                :caption: Deleting multiple blobs.
824        """
825        raise_on_any_failure = kwargs.pop('raise_on_any_failure', True)
826        timeout = kwargs.pop('timeout', None)
827        options = BlobClient._generic_delete_blob_options(  # pylint: disable=protected-access
828            delete_snapshots=delete_snapshots,
829            lease=lease,
830            timeout=timeout,
831            **kwargs
832        )
833        options.update({'raise_on_any_failure': raise_on_any_failure})
834        query_parameters, header_parameters = self._generate_delete_blobs_options(**options)
835        # To pass kwargs to "_batch_send", we need to remove anything that was
836        # in the Autorest signature for Autorest, otherwise transport will be upset
837        for possible_param in ['timeout', 'delete_snapshots', 'lease_access_conditions', 'modified_access_conditions']:
838            options.pop(possible_param, None)
839
840        reqs = []
841        for blob in blobs:
842            blob_name = _get_blob_name(blob)
843            req = HttpRequest(
844                "DELETE",
845                "/{}/{}".format(self.container_name, blob_name),
846                headers=header_parameters
847            )
848            req.format_parameters(query_parameters)
849            reqs.append(req)
850
851        return await self._batch_send(*reqs, **options)
852
853    @distributed_trace
854    async def set_standard_blob_tier_blobs(
855        self,
856        standard_blob_tier: Union[str, 'StandardBlobTier'],
857        *blobs: Union[str, BlobProperties],
858        **kwargs
859    ) -> AsyncIterator[AsyncHttpResponse]:
860        """This operation sets the tier on block blobs.
861
862        A block blob's tier determines Hot/Cool/Archive storage type.
863        This operation does not update the blob's ETag.
864
865        :param standard_blob_tier:
866            Indicates the tier to be set on the blob. Options include 'Hot', 'Cool',
867            'Archive'. The hot tier is optimized for storing data that is accessed
868            frequently. The cool storage tier is optimized for storing data that
869            is infrequently accessed and stored for at least a month. The archive
870            tier is optimized for storing data that is rarely accessed and stored
871            for at least six months with flexible latency requirements.
872        :type standard_blob_tier: str or ~azure.storage.blob.StandardBlobTier
873        :param blobs: The blobs with which to interact. This can be a single blob, or multiple values can
874            be supplied, where each value is either the name of the blob (str) or BlobProperties.
875        :type blobs: str or ~azure.storage.blob.BlobProperties
876        :keyword int timeout:
877            The timeout parameter is expressed in seconds.
878        :keyword lease:
879            Required if the blob has an active lease. Value can be a BlobLeaseClient object
880            or the lease ID as a string.
881        :paramtype lease: ~azure.storage.blob.aio.BlobLeaseClient or str
882        :keyword bool raise_on_any_failure:
883            This is a boolean param which defaults to True. When this is set, an exception
884            is raised even if there is a single operation failure. For optimal performance,
885            this should be set to False.
886        :return: An async iterator of responses, one for each blob in order
887        :rtype: asynciterator[~azure.core.pipeline.transport.AsyncHttpResponse]
888        """
889        access_conditions = get_access_conditions(kwargs.pop('lease', None))
890        if standard_blob_tier is None:
891            raise ValueError("A StandardBlobTier must be specified")
892
893        query_parameters, header_parameters = self._generate_set_tier_options(
894            tier=standard_blob_tier,
895            lease_access_conditions=access_conditions,
896            **kwargs
897        )
898        # To pass kwargs to "_batch_send", we need to remove anything that was
899        # in the Autorest signature for Autorest, otherwise transport will be upset
900        for possible_param in ['timeout', 'lease']:
901            kwargs.pop(possible_param, None)
902
903        reqs = []
904        for blob in blobs:
905            blob_name = _get_blob_name(blob)
906            req = HttpRequest(
907                "PUT",
908                "/{}/{}".format(self.container_name, blob_name),
909                headers=header_parameters
910            )
911            req.format_parameters(query_parameters)
912            reqs.append(req)
913
914        return await self._batch_send(*reqs, **kwargs)
915
916    @distributed_trace
917    async def set_premium_page_blob_tier_blobs(
918        self,
919        premium_page_blob_tier: Union[str, 'PremiumPageBlobTier'],
920        *blobs: Union[str, BlobProperties],
921        **kwargs
922    ) -> AsyncIterator[AsyncHttpResponse]:
923        """Sets the page blob tiers on the blobs. This API is only supported for page blobs on premium accounts.
924
925        :param premium_page_blob_tier:
926            A page blob tier value to set the blob to. The tier correlates to the size of the
927            blob and number of allowed IOPS. This is only applicable to page blobs on
928            premium storage accounts.
929        :type premium_page_blob_tier: ~azure.storage.blob.PremiumPageBlobTier
930        :param blobs: The blobs with which to interact. This can be a single blob, or multiple values can
931            be supplied, where each value is either the name of the blob (str) or BlobProperties.
932        :type blobs: str or ~azure.storage.blob.BlobProperties
933        :keyword int timeout:
934            The timeout parameter is expressed in seconds. This method may make
935            multiple calls to the Azure service and the timeout will apply to
936            each call individually.
937        :keyword lease:
938            Required if the blob has an active lease. Value can be a BlobLeaseClient object
939            or the lease ID as a string.
940        :paramtype lease: ~azure.storage.blob.aio.BlobLeaseClient or str
941        :keyword bool raise_on_any_failure:
942            This is a boolean param which defaults to True. When this is set, an exception
943            is raised even if there is a single operation failure. For optimal performance,
944            this should be set to False.
945        :return: An async iterator of responses, one for each blob in order
946        :rtype: asynciterator[~azure.core.pipeline.transport.AsyncHttpResponse]
947        """
948        access_conditions = get_access_conditions(kwargs.pop('lease', None))
949        if premium_page_blob_tier is None:
950            raise ValueError("A PremiumPageBlobTier must be specified")
951
952        query_parameters, header_parameters = self._generate_set_tier_options(
953            tier=premium_page_blob_tier,
954            lease_access_conditions=access_conditions,
955            **kwargs
956        )
957        # To pass kwargs to "_batch_send", we need to remove anything that was
958        # in the Autorest signature for Autorest, otherwise transport will be upset
959        for possible_param in ['timeout', 'lease']:
960            kwargs.pop(possible_param, None)
961
962        reqs = []
963        for blob in blobs:
964            blob_name = _get_blob_name(blob)
965            req = HttpRequest(
966                "PUT",
967                "/{}/{}".format(self.container_name, blob_name),
968                headers=header_parameters
969            )
970            req.format_parameters(query_parameters)
971            reqs.append(req)
972
973        return await self._batch_send(*reqs, **kwargs)
974
975    def get_blob_client(
976            self, blob,  # type: Union[BlobProperties, str]
977            snapshot=None  # type: str
978        ):
979        # type: (...) -> BlobClient
980        """Get a client to interact with the specified blob.
981
982        The blob need not already exist.
983
984        :param blob:
985            The blob with which to interact.
986        :type blob: str or ~azure.storage.blob.BlobProperties
987        :param str snapshot:
988            The optional blob snapshot on which to operate. This can be the snapshot ID string
989            or the response returned from :func:`~BlobClient.create_snapshot()`.
990        :returns: A BlobClient.
991        :rtype: ~azure.storage.blob.aio.BlobClient
992
993        .. admonition:: Example:
994
995            .. literalinclude:: ../samples/blob_samples_containers_async.py
996                :start-after: [START get_blob_client]
997                :end-before: [END get_blob_client]
998                :language: python
999                :dedent: 12
1000                :caption: Get the blob client.
1001        """
1002        blob_name = _get_blob_name(blob)
1003        _pipeline = AsyncPipeline(
1004            transport=AsyncTransportWrapper(self._pipeline._transport), # pylint: disable = protected-access
1005            policies=self._pipeline._impl_policies # pylint: disable = protected-access
1006        )
1007        return BlobClient(
1008            self.url, container_name=self.container_name, blob_name=blob_name, snapshot=snapshot,
1009            credential=self.credential, _configuration=self._config,
1010            _pipeline=_pipeline, _location_mode=self._location_mode, _hosts=self._hosts,
1011            require_encryption=self.require_encryption, key_encryption_key=self.key_encryption_key,
1012            key_resolver_function=self.key_resolver_function, loop=self._loop)
1013