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