1# ------------------------------------------------------------------------- 2# Copyright (c) Microsoft Corporation. All rights reserved. 3# Licensed under the MIT License. See License.txt in the project root for 4# license information. 5# -------------------------------------------------------------------------- 6# pylint: disable=too-many-lines, invalid-overridden-method, too-many-public-methods 7import functools 8import time 9from io import BytesIO 10from typing import Optional, Union, IO, List, Tuple, Dict, Any, Iterable, TYPE_CHECKING # pylint: disable=unused-import 11 12import six 13from azure.core.async_paging import AsyncItemPaged 14from azure.core.exceptions import HttpResponseError 15 16from azure.core.tracing.decorator import distributed_trace 17from azure.core.tracing.decorator_async import distributed_trace_async 18from .._parser import _datetime_to_str, _get_file_permission 19from .._shared.parser import _str 20 21from .._generated.aio import AzureFileStorage 22from .._generated.models import FileHTTPHeaders 23from .._shared.policies_async import ExponentialRetry 24from .._shared.uploads_async import upload_data_chunks, FileChunkUploader, IterStreamer 25from .._shared.base_client_async import AsyncStorageAccountHostsMixin 26from .._shared.request_handlers import add_metadata_headers, get_length 27from .._shared.response_handlers import return_response_headers, process_storage_error 28from .._deserialize import deserialize_file_properties, deserialize_file_stream, get_file_ranges_result 29from .._serialize import get_access_conditions, get_smb_properties, get_api_version 30from .._file_client import ShareFileClient as ShareFileClientBase 31from ._models import HandlesPaged 32from ._lease_async import ShareLeaseClient 33from ._download_async import StorageStreamDownloader 34 35if TYPE_CHECKING: 36 from datetime import datetime 37 from .._models import ShareProperties, ContentSettings, FileProperties, NTFSAttributes 38 from .._generated.models import HandleItem 39 40 41async def _upload_file_helper( 42 client, 43 stream, 44 size, 45 metadata, 46 content_settings, 47 validate_content, 48 timeout, 49 max_concurrency, 50 file_settings, 51 file_attributes="none", 52 file_creation_time="now", 53 file_last_write_time="now", 54 file_permission=None, 55 file_permission_key=None, 56 **kwargs 57): 58 try: 59 if size is None or size < 0: 60 raise ValueError("A content size must be specified for a File.") 61 response = await client.create_file( 62 size, content_settings=content_settings, metadata=metadata, 63 file_attributes=file_attributes, 64 file_creation_time=file_creation_time, 65 file_last_write_time=file_last_write_time, 66 file_permission=file_permission, 67 permission_key=file_permission_key, 68 timeout=timeout, 69 **kwargs 70 ) 71 if size == 0: 72 return response 73 74 responses = await upload_data_chunks( 75 service=client, 76 uploader_class=FileChunkUploader, 77 total_size=size, 78 chunk_size=file_settings.max_range_size, 79 stream=stream, 80 max_concurrency=max_concurrency, 81 validate_content=validate_content, 82 timeout=timeout, 83 **kwargs 84 ) 85 return sorted(responses, key=lambda r: r.get('last_modified'))[-1] 86 except HttpResponseError as error: 87 process_storage_error(error) 88 89 90class ShareFileClient(AsyncStorageAccountHostsMixin, ShareFileClientBase): 91 """A client to interact with a specific file, although that file may not yet exist. 92 93 :param str account_url: 94 The URI to the storage account. In order to create a client given the full URI to the 95 file, use the :func:`from_file_url` classmethod. 96 :param share_name: 97 The name of the share for the file. 98 :type share_name: str 99 :param str file_path: 100 The file path to the file with which to interact. If specified, this value will override 101 a file value specified in the file URL. 102 :param str snapshot: 103 An optional file snapshot on which to operate. This can be the snapshot ID string 104 or the response returned from :func:`ShareClient.create_snapshot`. 105 :param credential: 106 The credential with which to authenticate. This is optional if the 107 account URL already has a SAS token. The value can be a SAS token string, 108 an instance of a AzureSasCredential from azure.core.credentials or an account 109 shared access key. 110 :keyword str api_version: 111 The Storage API version to use for requests. Default value is '2019-07-07'. 112 Setting to an older version may result in reduced feature compatibility. 113 114 .. versionadded:: 12.1.0 115 116 :keyword str secondary_hostname: 117 The hostname of the secondary endpoint. 118 :keyword loop: 119 The event loop to run the asynchronous tasks. 120 :keyword int max_range_size: The maximum range size used for a file upload. Defaults to 4*1024*1024. 121 """ 122 123 def __init__( # type: ignore 124 self, 125 account_url, # type: str 126 share_name, # type: str 127 file_path, # type: str 128 snapshot=None, # type: Optional[Union[str, Dict[str, Any]]] 129 credential=None, # type: Optional[Any] 130 **kwargs # type: Any 131 ): 132 # type: (...) -> None 133 kwargs["retry_policy"] = kwargs.get("retry_policy") or ExponentialRetry(**kwargs) 134 loop = kwargs.pop('loop', None) 135 super(ShareFileClient, self).__init__( 136 account_url, share_name=share_name, file_path=file_path, snapshot=snapshot, 137 credential=credential, loop=loop, **kwargs 138 ) 139 self._client = AzureFileStorage(url=self.url, pipeline=self._pipeline, loop=loop) 140 default_api_version = self._client._config.version # pylint: disable=protected-access 141 self._client._config.version = get_api_version(kwargs, default_api_version) # pylint: disable=protected-access 142 self._loop = loop 143 144 @distributed_trace_async 145 async def acquire_lease(self, lease_id=None, **kwargs): 146 # type: (Optional[str], **Any) -> ShareLeaseClient 147 """Requests a new lease. 148 149 If the file does not have an active lease, the File 150 Service creates a lease on the blob and returns a new lease. 151 152 :param str lease_id: 153 Proposed lease ID, in a GUID string format. The File Service 154 returns 400 (Invalid request) if the proposed lease ID is not 155 in the correct format. 156 :keyword int timeout: 157 The timeout parameter is expressed in seconds. 158 :returns: A ShareLeaseClient object. 159 :rtype: ~azure.storage.fileshare.aio.ShareLeaseClient 160 161 .. admonition:: Example: 162 163 .. literalinclude:: ../samples/blob_samples_common.py 164 :start-after: [START acquire_lease_on_blob] 165 :end-before: [END acquire_lease_on_blob] 166 :language: python 167 :dedent: 8 168 :caption: Acquiring a lease on a blob. 169 """ 170 kwargs['lease_duration'] = -1 171 lease = ShareLeaseClient(self, lease_id=lease_id) # type: ignore 172 await lease.acquire(**kwargs) 173 return lease 174 175 @distributed_trace_async 176 async def create_file( # type: ignore 177 self, 178 size, # type: int 179 file_attributes="none", # type: Union[str, NTFSAttributes] 180 file_creation_time="now", # type: Union[str, datetime] 181 file_last_write_time="now", # type: Union[str, datetime] 182 file_permission=None, # type: Optional[str] 183 permission_key=None, # type: Optional[str] 184 **kwargs # type: Any 185 ): 186 # type: (...) -> Dict[str, Any] 187 """Creates a new file. 188 189 Note that it only initializes the file with no content. 190 191 :param int size: Specifies the maximum size for the file, 192 up to 1 TB. 193 :param file_attributes: 194 The file system attributes for files and directories. 195 If not set, the default value would be "None" and the attributes will be set to "Archive". 196 Here is an example for when the var type is str: 'Temporary|Archive'. 197 file_attributes value is not case sensitive. 198 :type file_attributes: str or :class:`~azure.storage.fileshare.NTFSAttributes` 199 :param file_creation_time: Creation time for the file 200 Default value: Now. 201 :type file_creation_time: str or ~datetime.datetime 202 :param file_last_write_time: Last write time for the file 203 Default value: Now. 204 :type file_last_write_time: str or ~datetime.datetime 205 :param file_permission: If specified the permission (security 206 descriptor) shall be set for the directory/file. This header can be 207 used if Permission size is <= 8KB, else x-ms-file-permission-key 208 header shall be used. Default value: Inherit. If SDDL is specified as 209 input, it must have owner, group and dacl. Note: Only one of the 210 x-ms-file-permission or x-ms-file-permission-key should be specified. 211 :type file_permission: str 212 :param permission_key: Key of the permission to be set for the 213 directory/file. Note: Only one of the x-ms-file-permission or 214 x-ms-file-permission-key should be specified. 215 :type permission_key: str 216 :keyword ~azure.storage.fileshare.ContentSettings content_settings: 217 ContentSettings object used to set file properties. Used to set content type, encoding, 218 language, disposition, md5, and cache control. 219 :keyword dict(str,str) metadata: 220 Name-value pairs associated with the file as metadata. 221 :keyword lease: 222 Required if the file has an active lease. Value can be a ShareLeaseClient object 223 or the lease ID as a string. 224 225 .. versionadded:: 12.1.0 226 227 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 228 :keyword int timeout: 229 The timeout parameter is expressed in seconds. 230 :returns: File-updated property dict (Etag and last modified). 231 :rtype: dict(str, Any) 232 233 .. admonition:: Example: 234 235 .. literalinclude:: ../samples/file_samples_client_async.py 236 :start-after: [START create_file] 237 :end-before: [END create_file] 238 :language: python 239 :dedent: 16 240 :caption: Create a file. 241 """ 242 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 243 content_settings = kwargs.pop('content_settings', None) 244 metadata = kwargs.pop('metadata', None) 245 timeout = kwargs.pop('timeout', None) 246 if self.require_encryption and not self.key_encryption_key: 247 raise ValueError("Encryption required but no key was provided.") 248 249 headers = kwargs.pop("headers", {}) 250 headers.update(add_metadata_headers(metadata)) 251 file_http_headers = None 252 if content_settings: 253 file_http_headers = FileHTTPHeaders( 254 file_cache_control=content_settings.cache_control, 255 file_content_type=content_settings.content_type, 256 file_content_md5=bytearray(content_settings.content_md5) if content_settings.content_md5 else None, 257 file_content_encoding=content_settings.content_encoding, 258 file_content_language=content_settings.content_language, 259 file_content_disposition=content_settings.content_disposition, 260 ) 261 file_permission = _get_file_permission(file_permission, permission_key, 'Inherit') 262 try: 263 return await self._client.file.create( # type: ignore 264 file_content_length=size, 265 metadata=metadata, 266 file_attributes=_str(file_attributes), 267 file_creation_time=_datetime_to_str(file_creation_time), 268 file_last_write_time=_datetime_to_str(file_last_write_time), 269 file_permission=file_permission, 270 file_permission_key=permission_key, 271 file_http_headers=file_http_headers, 272 lease_access_conditions=access_conditions, 273 headers=headers, 274 timeout=timeout, 275 cls=return_response_headers, 276 **kwargs 277 ) 278 except HttpResponseError as error: 279 process_storage_error(error) 280 281 @distributed_trace_async 282 async def upload_file( 283 self, data, # type: Any 284 length=None, # type: Optional[int] 285 file_attributes="none", # type: Union[str, NTFSAttributes] 286 file_creation_time="now", # type: Union[str, datetime] 287 file_last_write_time="now", # type: Union[str, datetime] 288 file_permission=None, # type: Optional[str] 289 permission_key=None, # type: Optional[str] 290 **kwargs # type: Any 291 ): 292 # type: (...) -> Dict[str, Any] 293 """Uploads a new file. 294 295 :param Any data: 296 Content of the file. 297 :param int length: 298 Length of the file in bytes. Specify its maximum size, up to 1 TiB. 299 :param file_attributes: 300 The file system attributes for files and directories. 301 If not set, the default value would be "None" and the attributes will be set to "Archive". 302 Here is an example for when the var type is str: 'Temporary|Archive'. 303 file_attributes value is not case sensitive. 304 :type file_attributes: str or ~azure.storage.fileshare.NTFSAttributes 305 :param file_creation_time: Creation time for the file 306 Default value: Now. 307 :type file_creation_time: str or ~datetime.datetime 308 :param file_last_write_time: Last write time for the file 309 Default value: Now. 310 :type file_last_write_time: str or ~datetime.datetime 311 :param file_permission: If specified the permission (security 312 descriptor) shall be set for the directory/file. This header can be 313 used if Permission size is <= 8KB, else x-ms-file-permission-key 314 header shall be used. Default value: Inherit. If SDDL is specified as 315 input, it must have owner, group and dacl. Note: Only one of the 316 x-ms-file-permission or x-ms-file-permission-key should be specified. 317 :type file_permission: str 318 :param permission_key: Key of the permission to be set for the 319 directory/file. Note: Only one of the x-ms-file-permission or 320 x-ms-file-permission-key should be specified. 321 :type permission_key: str 322 :keyword dict(str,str) metadata: 323 Name-value pairs associated with the file as metadata. 324 :keyword ~azure.storage.fileshare.ContentSettings content_settings: 325 ContentSettings object used to set file properties. Used to set content type, encoding, 326 language, disposition, md5, and cache control. 327 :keyword bool validate_content: 328 If true, calculates an MD5 hash for each range of the file. The storage 329 service checks the hash of the content that has arrived with the hash 330 that was sent. This is primarily valuable for detecting bitflips on 331 the wire if using http instead of https as https (the default) will 332 already validate. Note that this MD5 hash is not stored with the 333 file. 334 :keyword int max_concurrency: 335 Maximum number of parallel connections to use. 336 :keyword str encoding: 337 Defaults to UTF-8. 338 :keyword lease: 339 Required if the file has an active lease. Value can be a ShareLeaseClient object 340 or the lease ID as a string. 341 342 .. versionadded:: 12.1.0 343 344 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 345 :keyword int timeout: 346 The timeout parameter is expressed in seconds. 347 :returns: File-updated property dict (Etag and last modified). 348 :rtype: dict(str, Any) 349 350 .. admonition:: Example: 351 352 .. literalinclude:: ../samples/file_samples_client_async.py 353 :start-after: [START upload_file] 354 :end-before: [END upload_file] 355 :language: python 356 :dedent: 16 357 :caption: Upload a file. 358 """ 359 metadata = kwargs.pop('metadata', None) 360 content_settings = kwargs.pop('content_settings', None) 361 max_concurrency = kwargs.pop('max_concurrency', 1) 362 validate_content = kwargs.pop('validate_content', False) 363 timeout = kwargs.pop('timeout', None) 364 encoding = kwargs.pop('encoding', 'UTF-8') 365 if self.require_encryption or (self.key_encryption_key is not None): 366 raise ValueError("Encryption not supported.") 367 368 if isinstance(data, six.text_type): 369 data = data.encode(encoding) 370 if length is None: 371 length = get_length(data) 372 if isinstance(data, bytes): 373 data = data[:length] 374 375 if isinstance(data, bytes): 376 stream = BytesIO(data) 377 elif hasattr(data, "read"): 378 stream = data 379 elif hasattr(data, "__iter__"): 380 stream = IterStreamer(data, encoding=encoding) # type: ignore 381 else: 382 raise TypeError("Unsupported data type: {}".format(type(data))) 383 return await _upload_file_helper( # type: ignore 384 self, 385 stream, 386 length, 387 metadata, 388 content_settings, 389 validate_content, 390 timeout, 391 max_concurrency, 392 self._config, 393 file_attributes=file_attributes, 394 file_creation_time=file_creation_time, 395 file_last_write_time=file_last_write_time, 396 file_permission=file_permission, 397 file_permission_key=permission_key, 398 **kwargs 399 ) 400 401 @distributed_trace_async 402 async def start_copy_from_url(self, source_url, **kwargs): 403 # type: (str, Any) -> Any 404 """Initiates the copying of data from a source URL into the file 405 referenced by the client. 406 407 The status of this copy operation can be found using the `get_properties` 408 method. 409 410 :param str source_url: 411 Specifies the URL of the source file. 412 :keyword str file_permission: 413 If specified the permission (security descriptor) shall be set for the directory/file. 414 This value can be set to "source" to copy the security descriptor from the source file. 415 Otherwise if set, this value will be used to override the source value. If not set, permission value 416 is inherited from the parent directory of the target file. This setting can be 417 used if Permission size is <= 8KB, otherwise permission_key shall be used. 418 If SDDL is specified as input, it must have owner, group and dacl. 419 Note: Only one of the file_permission or permission_key should be specified. 420 421 .. versionadded:: 12.1.0 422 This parameter was introduced in API version '2019-07-07'. 423 424 :keyword str permission_key: 425 Key of the permission to be set for the directory/file. 426 This value can be set to "source" to copy the security descriptor from the source file. 427 Otherwise if set, this value will be used to override the source value. If not set, permission value 428 is inherited from the parent directory of the target file. 429 Note: Only one of the file_permission or permission_key should be specified. 430 431 .. versionadded:: 12.1.0 432 This parameter was introduced in API version '2019-07-07'. 433 434 :keyword file_attributes: 435 This value can be set to "source" to copy file attributes from the source file to the target file, 436 or to clear all attributes, it can be set to "None". Otherwise it can be set to a list of attributes 437 to set on the target file. If this is not set, the default value is "Archive". 438 439 .. versionadded:: 12.1.0 440 This parameter was introduced in API version '2019-07-07'. 441 442 :paramtype file_attributes: str or :class:`~azure.storage.fileshare.NTFSAttributes` 443 :keyword file_creation_time: 444 This value can be set to "source" to copy the creation time from the source file to the target file, 445 or a datetime to set as creation time on the target file. This could also be a string in ISO 8601 format. 446 If this is not set, creation time will be set to the date time value of the creation 447 (or when it was overwritten) of the target file by copy engine. 448 449 .. versionadded:: 12.1.0 450 This parameter was introduced in API version '2019-07-07'. 451 452 :paramtype file_creation_time: str or ~datetime.datetime 453 :keyword file_last_write_time: 454 This value can be set to "source" to copy the last write time from the source file to the target file, or 455 a datetime to set as the last write time on the target file. This could also be a string in ISO 8601 format. 456 If this is not set, value will be the last write time to the file by the copy engine. 457 458 .. versionadded:: 12.1.0 459 This parameter was introduced in API version '2019-07-07'. 460 461 :paramtype file_last_write_time: str or ~datetime.datetime 462 :keyword bool ignore_read_only: 463 Specifies the option to overwrite the target file if it already exists and has read-only attribute set. 464 465 .. versionadded:: 12.1.0 466 This parameter was introduced in API version '2019-07-07'. 467 468 :keyword bool set_archive_attribute: 469 Specifies the option to set the archive attribute on the target file. 470 True means the archive attribute will be set on the target file despite attribute 471 overrides or the source file state. 472 473 .. versionadded:: 12.1.0 474 This parameter was introduced in API version '2019-07-07'. 475 476 :keyword metadata: 477 Name-value pairs associated with the file as metadata. 478 :type metadata: dict(str, str) 479 :keyword lease: 480 Required if the file has an active lease. Value can be a ShareLeaseClient object 481 or the lease ID as a string. 482 483 .. versionadded:: 12.1.0 484 485 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 486 :keyword int timeout: 487 The timeout parameter is expressed in seconds. 488 :rtype: dict(str, Any) 489 490 .. admonition:: Example: 491 492 .. literalinclude:: ../samples/file_samples_client_async.py 493 :start-after: [START copy_file_from_url] 494 :end-before: [END copy_file_from_url] 495 :language: python 496 :dedent: 16 497 :caption: Copy a file from a URL 498 """ 499 metadata = kwargs.pop('metadata', None) 500 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 501 timeout = kwargs.pop('timeout', None) 502 headers = kwargs.pop("headers", {}) 503 headers.update(add_metadata_headers(metadata)) 504 kwargs.update(get_smb_properties(kwargs)) 505 try: 506 return await self._client.file.start_copy( 507 source_url, 508 metadata=metadata, 509 lease_access_conditions=access_conditions, 510 headers=headers, 511 cls=return_response_headers, 512 timeout=timeout, 513 **kwargs 514 ) 515 except HttpResponseError as error: 516 process_storage_error(error) 517 518 @distributed_trace_async 519 async def abort_copy(self, copy_id, **kwargs): 520 # type: (Union[str, FileProperties], Any) -> None 521 """Abort an ongoing copy operation. 522 523 This will leave a destination file with zero length and full metadata. 524 This will raise an error if the copy operation has already ended. 525 526 :param copy_id: 527 The copy operation to abort. This can be either an ID, or an 528 instance of FileProperties. 529 :type copy_id: str or ~azure.storage.fileshare.FileProperties 530 :keyword lease: 531 Required if the file has an active lease. Value can be a ShareLeaseClient object 532 or the lease ID as a string. 533 534 .. versionadded:: 12.1.0 535 536 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 537 :keyword int timeout: 538 The timeout parameter is expressed in seconds. 539 :rtype: None 540 """ 541 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 542 timeout = kwargs.pop('timeout', None) 543 try: 544 copy_id = copy_id.copy.id 545 except AttributeError: 546 try: 547 copy_id = copy_id["copy_id"] 548 except TypeError: 549 pass 550 try: 551 await self._client.file.abort_copy(copy_id=copy_id, 552 lease_access_conditions=access_conditions, 553 timeout=timeout, **kwargs) 554 except HttpResponseError as error: 555 process_storage_error(error) 556 557 @distributed_trace_async 558 async def download_file( 559 self, 560 offset=None, # type: Optional[int] 561 length=None, # type: Optional[int] 562 **kwargs 563 ): 564 # type: (...) -> Iterable[bytes] 565 """Downloads a file to a stream with automatic chunking. 566 567 :param int offset: 568 Start of byte range to use for downloading a section of the file. 569 Must be set if length is provided. 570 :param int length: 571 Number of bytes to read from the stream. This is optional, but 572 should be supplied for optimal performance. 573 :keyword int max_concurrency: 574 Maximum number of parallel connections to use. 575 :keyword bool validate_content: 576 If true, calculates an MD5 hash for each chunk of the file. The storage 577 service checks the hash of the content that has arrived with the hash 578 that was sent. This is primarily valuable for detecting bitflips on 579 the wire if using http instead of https as https (the default) will 580 already validate. Note that this MD5 hash is not stored with the 581 file. Also note that if enabled, the memory-efficient upload algorithm 582 will not be used, because computing the MD5 hash requires buffering 583 entire blocks, and doing so defeats the purpose of the memory-efficient algorithm. 584 :keyword lease: 585 Required if the file has an active lease. Value can be a ShareLeaseClient object 586 or the lease ID as a string. 587 588 .. versionadded:: 12.1.0 589 590 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 591 :keyword int timeout: 592 The timeout parameter is expressed in seconds. 593 :returns: A iterable data generator (stream) 594 595 .. admonition:: Example: 596 597 .. literalinclude:: ../samples/file_samples_client_async.py 598 :start-after: [START download_file] 599 :end-before: [END download_file] 600 :language: python 601 :dedent: 16 602 :caption: Download a file. 603 """ 604 if self.require_encryption or (self.key_encryption_key is not None): 605 raise ValueError("Encryption not supported.") 606 if length is not None and offset is None: 607 raise ValueError("Offset value must not be None if length is set.") 608 609 range_end = None 610 if length is not None: 611 range_end = offset + length - 1 # Service actually uses an end-range inclusive index 612 613 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 614 615 downloader = StorageStreamDownloader( 616 client=self._client.file, 617 config=self._config, 618 start_range=offset, 619 end_range=range_end, 620 encryption_options=None, 621 name=self.file_name, 622 path='/'.join(self.file_path), 623 share=self.share_name, 624 lease_access_conditions=access_conditions, 625 cls=deserialize_file_stream, 626 **kwargs 627 ) 628 await downloader._setup() # pylint: disable=protected-access 629 return downloader 630 631 @distributed_trace_async 632 async def delete_file(self, **kwargs): 633 # type: (Any) -> None 634 """Marks the specified file for deletion. The file is 635 later deleted during garbage collection. 636 637 :keyword lease: 638 Required if the file has an active lease. Value can be a ShareLeaseClient object 639 or the lease ID as a string. 640 641 .. versionadded:: 12.1.0 642 643 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 644 :keyword int timeout: 645 The timeout parameter is expressed in seconds. 646 :rtype: None 647 648 .. admonition:: Example: 649 650 .. literalinclude:: ../samples/file_samples_client_async.py 651 :start-after: [START delete_file] 652 :end-before: [END delete_file] 653 :language: python 654 :dedent: 16 655 :caption: Delete a file. 656 """ 657 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 658 timeout = kwargs.pop('timeout', None) 659 try: 660 await self._client.file.delete(lease_access_conditions=access_conditions, timeout=timeout, **kwargs) 661 except HttpResponseError as error: 662 process_storage_error(error) 663 664 @distributed_trace_async 665 async def get_file_properties(self, **kwargs): 666 # type: (Any) -> FileProperties 667 """Returns all user-defined metadata, standard HTTP properties, and 668 system properties for the file. 669 670 :keyword lease: 671 Required if the file has an active lease. Value can be a ShareLeaseClient object 672 or the lease ID as a string. 673 674 .. versionadded:: 12.1.0 675 676 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 677 :keyword int timeout: 678 The timeout parameter is expressed in seconds. 679 :returns: FileProperties 680 :rtype: ~azure.storage.fileshare.FileProperties 681 """ 682 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 683 timeout = kwargs.pop('timeout', None) 684 try: 685 file_props = await self._client.file.get_properties( 686 sharesnapshot=self.snapshot, 687 lease_access_conditions=access_conditions, 688 timeout=timeout, 689 cls=deserialize_file_properties, 690 **kwargs 691 ) 692 except HttpResponseError as error: 693 process_storage_error(error) 694 file_props.name = self.file_name 695 file_props.share = self.share_name 696 file_props.snapshot = self.snapshot 697 file_props.path = "/".join(self.file_path) 698 return file_props # type: ignore 699 700 @distributed_trace_async 701 async def set_http_headers(self, content_settings, # type: ContentSettings 702 file_attributes="preserve", # type: Union[str, NTFSAttributes] 703 file_creation_time="preserve", # type: Union[str, datetime] 704 file_last_write_time="preserve", # type: Union[str, datetime] 705 file_permission=None, # type: Optional[str] 706 permission_key=None, # type: Optional[str] 707 **kwargs # type: Any 708 ): 709 # type: (...) -> Dict[str, Any] 710 """Sets HTTP headers on the file. 711 712 :param ~azure.storage.fileshare.ContentSettings content_settings: 713 ContentSettings object used to set file properties. Used to set content type, encoding, 714 language, disposition, md5, and cache control. 715 :param file_attributes: 716 The file system attributes for files and directories. 717 If not set, indicates preservation of existing values. 718 Here is an example for when the var type is str: 'Temporary|Archive' 719 :type file_attributes: str or :class:`~azure.storage.fileshare.NTFSAttributes` 720 :param file_creation_time: Creation time for the file 721 Default value: Preserve. 722 :type file_creation_time: str or ~datetime.datetime 723 :param file_last_write_time: Last write time for the file 724 Default value: Preserve. 725 :type file_last_write_time: str or ~datetime.datetime 726 :param file_permission: If specified the permission (security 727 descriptor) shall be set for the directory/file. This header can be 728 used if Permission size is <= 8KB, else x-ms-file-permission-key 729 header shall be used. Default value: Inherit. If SDDL is specified as 730 input, it must have owner, group and dacl. Note: Only one of the 731 x-ms-file-permission or x-ms-file-permission-key should be specified. 732 :type file_permission: str 733 :param permission_key: Key of the permission to be set for the 734 directory/file. Note: Only one of the x-ms-file-permission or 735 x-ms-file-permission-key should be specified. 736 :type permission_key: str 737 :keyword lease: 738 Required if the file has an active lease. Value can be a ShareLeaseClient object 739 or the lease ID as a string. 740 741 .. versionadded:: 12.1.0 742 743 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 744 :keyword int timeout: 745 The timeout parameter is expressed in seconds. 746 :returns: File-updated property dict (Etag and last modified). 747 :rtype: dict(str, Any) 748 """ 749 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 750 timeout = kwargs.pop('timeout', None) 751 file_content_length = kwargs.pop("size", None) 752 file_http_headers = FileHTTPHeaders( 753 file_cache_control=content_settings.cache_control, 754 file_content_type=content_settings.content_type, 755 file_content_md5=bytearray(content_settings.content_md5) if content_settings.content_md5 else None, 756 file_content_encoding=content_settings.content_encoding, 757 file_content_language=content_settings.content_language, 758 file_content_disposition=content_settings.content_disposition, 759 ) 760 file_permission = _get_file_permission(file_permission, permission_key, 'preserve') 761 try: 762 return await self._client.file.set_http_headers( # type: ignore 763 file_content_length=file_content_length, 764 file_http_headers=file_http_headers, 765 file_attributes=_str(file_attributes), 766 file_creation_time=_datetime_to_str(file_creation_time), 767 file_last_write_time=_datetime_to_str(file_last_write_time), 768 file_permission=file_permission, 769 file_permission_key=permission_key, 770 lease_access_conditions=access_conditions, 771 timeout=timeout, 772 cls=return_response_headers, 773 **kwargs 774 ) 775 except HttpResponseError as error: 776 process_storage_error(error) 777 778 @distributed_trace_async 779 async def set_file_metadata(self, metadata=None, **kwargs): # type: ignore 780 # type: (Optional[Dict[str, Any]], Any) -> Dict[str, Any] 781 """Sets user-defined metadata for the specified file as one or more 782 name-value pairs. 783 784 Each call to this operation replaces all existing metadata 785 attached to the file. To remove all metadata from the file, 786 call this operation with no metadata dict. 787 788 :param metadata: 789 Name-value pairs associated with the file as metadata. 790 :type metadata: dict(str, str) 791 :keyword lease: 792 Required if the file has an active lease. Value can be a ShareLeaseClient object 793 or the lease ID as a string. 794 795 .. versionadded:: 12.1.0 796 797 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 798 :keyword int timeout: 799 The timeout parameter is expressed in seconds. 800 :returns: File-updated property dict (Etag and last modified). 801 :rtype: dict(str, Any) 802 """ 803 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 804 timeout = kwargs.pop('timeout', None) 805 headers = kwargs.pop("headers", {}) 806 headers.update(add_metadata_headers(metadata)) # type: ignore 807 try: 808 return await self._client.file.set_metadata( # type: ignore 809 metadata=metadata, lease_access_conditions=access_conditions, 810 timeout=timeout, cls=return_response_headers, headers=headers, **kwargs 811 ) 812 except HttpResponseError as error: 813 process_storage_error(error) 814 815 @distributed_trace_async 816 async def upload_range( # type: ignore 817 self, 818 data, # type: bytes 819 offset, # type: int 820 length, # type: int 821 **kwargs 822 ): 823 # type: (...) -> Dict[str, Any] 824 """Upload a range of bytes to a file. 825 826 :param bytes data: 827 The data to upload. 828 :param int offset: 829 Start of byte range to use for uploading a section of the file. 830 The range can be up to 4 MB in size. 831 :param int length: 832 Number of bytes to use for uploading a section of the file. 833 The range can be up to 4 MB in size. 834 :keyword bool validate_content: 835 If true, calculates an MD5 hash of the page content. The storage 836 service checks the hash of the content that has arrived 837 with the hash that was sent. This is primarily valuable for detecting 838 bitflips on the wire if using http instead of https as https (the default) 839 will already validate. Note that this MD5 hash is not stored with the 840 file. 841 :keyword lease: 842 Required if the file has an active lease. Value can be a ShareLeaseClient object 843 or the lease ID as a string. 844 845 .. versionadded:: 12.1.0 846 847 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 848 :keyword int timeout: 849 The timeout parameter is expressed in seconds. 850 :keyword str encoding: 851 Defaults to UTF-8. 852 :returns: File-updated property dict (Etag and last modified). 853 :rtype: Dict[str, Any] 854 """ 855 validate_content = kwargs.pop('validate_content', False) 856 timeout = kwargs.pop('timeout', None) 857 encoding = kwargs.pop('encoding', 'UTF-8') 858 if self.require_encryption or (self.key_encryption_key is not None): 859 raise ValueError("Encryption not supported.") 860 if isinstance(data, six.text_type): 861 data = data.encode(encoding) 862 end_range = offset + length - 1 # Reformat to an inclusive range index 863 content_range = 'bytes={0}-{1}'.format(offset, end_range) 864 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 865 try: 866 return await self._client.file.upload_range( # type: ignore 867 range=content_range, 868 content_length=length, 869 optionalbody=data, 870 timeout=timeout, 871 validate_content=validate_content, 872 lease_access_conditions=access_conditions, 873 cls=return_response_headers, 874 **kwargs 875 ) 876 except HttpResponseError as error: 877 process_storage_error(error) 878 879 @distributed_trace_async 880 async def upload_range_from_url(self, source_url, 881 offset, 882 length, 883 source_offset, 884 **kwargs 885 ): 886 # type: (str, int, int, int, **Any) -> Dict[str, Any] 887 """ 888 Writes the bytes from one Azure File endpoint into the specified range of another Azure File endpoint. 889 890 :param int offset: 891 Start of byte range to use for updating a section of the file. 892 The range can be up to 4 MB in size. 893 :param int length: 894 Number of bytes to use for updating a section of the file. 895 The range can be up to 4 MB in size. 896 :param str source_url: 897 A URL of up to 2 KB in length that specifies an Azure file or blob. 898 The value should be URL-encoded as it would appear in a request URI. 899 If the source is in another account, the source must either be public 900 or must be authenticated via a shared access signature. If the source 901 is public, no authentication is required. 902 Examples: 903 https://myaccount.file.core.windows.net/myshare/mydir/myfile 904 https://otheraccount.file.core.windows.net/myshare/mydir/myfile?sastoken 905 :param int source_offset: 906 This indicates the start of the range of bytes(inclusive) that has to be taken from the copy source. 907 The service will read the same number of bytes as the destination range (length-offset). 908 :keyword lease: 909 Required if the file has an active lease. Value can be a ShareLeaseClient object 910 or the lease ID as a string. 911 912 .. versionadded:: 12.1.0 913 914 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 915 :keyword int timeout: 916 The timeout parameter is expressed in seconds. 917 """ 918 options = self._upload_range_from_url_options( 919 source_url=source_url, 920 offset=offset, 921 length=length, 922 source_offset=source_offset, 923 **kwargs 924 ) 925 try: 926 return await self._client.file.upload_range_from_url(**options) # type: ignore 927 except HttpResponseError as error: 928 process_storage_error(error) 929 930 @distributed_trace_async 931 async def get_ranges( # type: ignore 932 self, offset=None, # type: Optional[int] 933 length=None, # type: Optional[int] 934 **kwargs # type: Any 935 ): 936 # type: (...) -> List[Dict[str, int]] 937 """Returns the list of valid page ranges for a file or snapshot 938 of a file. 939 940 :param int offset: 941 Specifies the start offset of bytes over which to get ranges. 942 :param int length: 943 Number of bytes to use over which to get ranges. 944 :keyword lease: 945 Required if the file has an active lease. Value can be a ShareLeaseClient object 946 or the lease ID as a string. 947 948 .. versionadded:: 12.1.0 949 950 :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str 951 :keyword int timeout: 952 The timeout parameter is expressed in seconds. 953 :returns: 954 A list of valid ranges. 955 :rtype: List[dict[str, int]] 956 """ 957 options = self._get_ranges_options( 958 offset=offset, 959 length=length, 960 **kwargs) 961 try: 962 ranges = await self._client.file.get_range_list(**options) 963 except HttpResponseError as error: 964 process_storage_error(error) 965 return [{'start': file_range.start, 'end': file_range.end} for file_range in ranges.ranges] 966 967 @distributed_trace_async 968 async def get_ranges_diff( # type: ignore 969 self, 970 previous_sharesnapshot, # type: Union[str, Dict[str, Any]] 971 offset=None, # type: Optional[int] 972 length=None, # type: Optional[int] 973 **kwargs # type: Any 974 ): 975 # type: (...) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]] 976 """Returns the list of valid page ranges for a file or snapshot 977 of a file. 978 979 .. versionadded:: 12.6.0 980 981 :param int offset: 982 Specifies the start offset of bytes over which to get ranges. 983 :param int length: 984 Number of bytes to use over which to get ranges. 985 :param str previous_sharesnapshot: 986 The snapshot diff parameter that contains an opaque DateTime value that 987 specifies a previous file snapshot to be compared 988 against a more recent snapshot or the current file. 989 :keyword lease: 990 Required if the file has an active lease. Value can be a ShareLeaseClient object 991 or the lease ID as a string. 992 :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str 993 :keyword int timeout: 994 The timeout parameter is expressed in seconds. 995 :returns: 996 A tuple of two lists of file ranges as dictionaries with 'start' and 'end' keys. 997 The first element are filled file ranges, the 2nd element is cleared file ranges. 998 :rtype: tuple(list(dict(str, str), list(dict(str, str)) 999 """ 1000 options = self._get_ranges_options( 1001 offset=offset, 1002 length=length, 1003 previous_sharesnapshot=previous_sharesnapshot, 1004 **kwargs) 1005 try: 1006 ranges = await self._client.file.get_range_list(**options) 1007 except HttpResponseError as error: 1008 process_storage_error(error) 1009 return get_file_ranges_result(ranges) 1010 1011 @distributed_trace_async 1012 async def clear_range( # type: ignore 1013 self, 1014 offset, # type: int 1015 length, # type: int 1016 **kwargs 1017 ): 1018 # type: (...) -> Dict[str, Any] 1019 """Clears the specified range and releases the space used in storage for 1020 that range. 1021 1022 :param int offset: 1023 Start of byte range to use for clearing a section of the file. 1024 The range can be up to 4 MB in size. 1025 :param int length: 1026 Number of bytes to use for clearing a section of the file. 1027 The range can be up to 4 MB in size. 1028 :keyword lease: 1029 Required if the file has an active lease. Value can be a ShareLeaseClient object 1030 or the lease ID as a string. 1031 1032 .. versionadded:: 12.1.0 1033 1034 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 1035 :keyword int timeout: 1036 The timeout parameter is expressed in seconds. 1037 :returns: File-updated property dict (Etag and last modified). 1038 :rtype: Dict[str, Any] 1039 """ 1040 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 1041 timeout = kwargs.pop('timeout', None) 1042 if self.require_encryption or (self.key_encryption_key is not None): 1043 raise ValueError("Unsupported method for encryption.") 1044 1045 if offset is None or offset % 512 != 0: 1046 raise ValueError("offset must be an integer that aligns with 512 bytes file size") 1047 if length is None or length % 512 != 0: 1048 raise ValueError("length must be an integer that aligns with 512 bytes file size") 1049 end_range = length + offset - 1 # Reformat to an inclusive range index 1050 content_range = "bytes={0}-{1}".format(offset, end_range) 1051 try: 1052 return await self._client.file.upload_range( # type: ignore 1053 timeout=timeout, 1054 cls=return_response_headers, 1055 content_length=0, 1056 optionalbody=None, 1057 file_range_write="clear", 1058 range=content_range, 1059 lease_access_conditions=access_conditions, 1060 **kwargs 1061 ) 1062 except HttpResponseError as error: 1063 process_storage_error(error) 1064 1065 @distributed_trace_async 1066 async def resize_file(self, size, **kwargs): 1067 # type: (int, Any) -> Dict[str, Any] 1068 """Resizes a file to the specified size. 1069 1070 :param int size: 1071 Size to resize file to (in bytes) 1072 :keyword lease: 1073 Required if the file has an active lease. Value can be a ShareLeaseClient object 1074 or the lease ID as a string. 1075 1076 .. versionadded:: 12.1.0 1077 1078 :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str 1079 :keyword int timeout: 1080 The timeout parameter is expressed in seconds. 1081 :returns: File-updated property dict (Etag and last modified). 1082 :rtype: Dict[str, Any] 1083 """ 1084 access_conditions = get_access_conditions(kwargs.pop('lease', None)) 1085 timeout = kwargs.pop('timeout', None) 1086 try: 1087 return await self._client.file.set_http_headers( # type: ignore 1088 file_content_length=size, 1089 file_attributes="preserve", 1090 file_creation_time="preserve", 1091 file_last_write_time="preserve", 1092 file_permission="preserve", 1093 lease_access_conditions=access_conditions, 1094 cls=return_response_headers, 1095 timeout=timeout, 1096 **kwargs 1097 ) 1098 except HttpResponseError as error: 1099 process_storage_error(error) 1100 1101 @distributed_trace 1102 def list_handles(self, **kwargs): 1103 # type: (Any) -> AsyncItemPaged 1104 """Lists handles for file. 1105 1106 :keyword int timeout: 1107 The timeout parameter is expressed in seconds. 1108 :returns: An auto-paging iterable of HandleItem 1109 :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.storage.fileshare.HandleItem] 1110 """ 1111 timeout = kwargs.pop('timeout', None) 1112 results_per_page = kwargs.pop("results_per_page", None) 1113 command = functools.partial( 1114 self._client.file.list_handles, 1115 sharesnapshot=self.snapshot, 1116 timeout=timeout, 1117 **kwargs) 1118 return AsyncItemPaged( 1119 command, results_per_page=results_per_page, 1120 page_iterator_class=HandlesPaged) 1121 1122 @distributed_trace_async 1123 async def close_handle(self, handle, **kwargs): 1124 # type: (Union[str, HandleItem], Any) -> Dict[str, int] 1125 """Close an open file handle. 1126 1127 :param handle: 1128 A specific handle to close. 1129 :type handle: str or ~azure.storage.fileshare.Handle 1130 :keyword int timeout: 1131 The timeout parameter is expressed in seconds. 1132 :returns: 1133 The number of handles closed (this may be 0 if the specified handle was not found) 1134 and the number of handles failed to close in a dict. 1135 :rtype: dict[str, int] 1136 """ 1137 try: 1138 handle_id = handle.id # type: ignore 1139 except AttributeError: 1140 handle_id = handle 1141 if handle_id == '*': 1142 raise ValueError("Handle ID '*' is not supported. Use 'close_all_handles' instead.") 1143 try: 1144 response = await self._client.file.force_close_handles( 1145 handle_id, 1146 marker=None, 1147 sharesnapshot=self.snapshot, 1148 cls=return_response_headers, 1149 **kwargs 1150 ) 1151 return { 1152 'closed_handles_count': response.get('number_of_handles_closed', 0), 1153 'failed_handles_count': response.get('number_of_handles_failed', 0) 1154 } 1155 except HttpResponseError as error: 1156 process_storage_error(error) 1157 1158 @distributed_trace_async 1159 async def close_all_handles(self, **kwargs): 1160 # type: (Any) -> Dict[str, int] 1161 """Close any open file handles. 1162 1163 This operation will block until the service has closed all open handles. 1164 1165 :keyword int timeout: 1166 The timeout parameter is expressed in seconds. 1167 :returns: 1168 The number of handles closed (this may be 0 if the specified handle was not found) 1169 and the number of handles failed to close in a dict. 1170 :rtype: dict[str, int] 1171 """ 1172 timeout = kwargs.pop('timeout', None) 1173 start_time = time.time() 1174 1175 try_close = True 1176 continuation_token = None 1177 total_closed = 0 1178 total_failed = 0 1179 while try_close: 1180 try: 1181 response = await self._client.file.force_close_handles( 1182 handle_id='*', 1183 timeout=timeout, 1184 marker=continuation_token, 1185 sharesnapshot=self.snapshot, 1186 cls=return_response_headers, 1187 **kwargs 1188 ) 1189 except HttpResponseError as error: 1190 process_storage_error(error) 1191 continuation_token = response.get('marker') 1192 try_close = bool(continuation_token) 1193 total_closed += response.get('number_of_handles_closed', 0) 1194 total_failed += response.get('number_of_handles_failed', 0) 1195 if timeout: 1196 timeout = max(0, timeout - (time.time() - start_time)) 1197 return { 1198 'closed_handles_count': total_closed, 1199 'failed_handles_count': total_failed 1200 } 1201