diff options
author | S. Solomon Darnell | 2025-03-28 21:52:21 -0500 |
---|---|---|
committer | S. Solomon Darnell | 2025-03-28 21:52:21 -0500 |
commit | 4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch) | |
tree | ee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/azure/storage/fileshare | |
parent | cc961e04ba734dd72309fb548a2f97d67d578813 (diff) | |
download | gn-ai-master.tar.gz |
Diffstat (limited to '.venv/lib/python3.12/site-packages/azure/storage/fileshare')
66 files changed, 35950 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/__init__.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/__init__.py new file mode 100644 index 00000000..be8da9c2 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/__init__.py @@ -0,0 +1,99 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import warnings + +from ._version import VERSION +from ._file_client import ShareFileClient +from ._directory_client import ShareDirectoryClient +from ._share_client import ShareClient +from ._share_service_client import ShareServiceClient +from ._lease import ShareLeaseClient +from ._shared_access_signature import generate_account_sas, generate_share_sas, generate_file_sas +from ._shared.policies import ExponentialRetry, LinearRetry +from ._shared.models import ( + LocationMode, + ResourceTypes, + AccountSasPermissions, + StorageErrorCode, + Services, +) +from ._models import ( + ShareProperties, + DirectoryProperties, + Handle, + FileProperties, + Metrics, + RetentionPolicy, + CorsRule, + ShareSmbSettings, + SmbMultichannel, + ShareProtocolSettings, + ShareProtocols, + AccessPolicy, + FileSasPermissions, + ShareSasPermissions, + ContentSettings, + NTFSAttributes, +) +from ._generated.models import ( + ShareAccessTier, + ShareRootSquash +) + +__version__ = VERSION + + +__all__ = [ + 'ShareFileClient', + 'ShareDirectoryClient', + 'ShareClient', + 'ShareServiceClient', + 'ShareLeaseClient', + 'ExponentialRetry', + 'LinearRetry', + 'LocationMode', + 'ResourceTypes', + 'AccountSasPermissions', + 'StorageErrorCode', + 'Metrics', + 'RetentionPolicy', + 'CorsRule', + 'ShareSmbSettings', + 'ShareAccessTier', + 'SmbMultichannel', + 'ShareProtocolSettings', + 'AccessPolicy', + 'FileSasPermissions', + 'ShareSasPermissions', + 'ShareProtocols', + 'ShareProperties', + 'DirectoryProperties', + 'FileProperties', + 'ContentSettings', + 'Handle', + 'NTFSAttributes', + 'ShareRootSquash', + 'generate_account_sas', + 'generate_share_sas', + 'generate_file_sas', + 'Services' +] + + +# This function is added to deal with HandleItem which is a generated model that +# was mistakenly added to the module exports. It has been removed import and __all__ +# to prevent it from showing in intellisense/docs but we handle it here to prevent +# breaking any existing code which may have imported it. +def __getattr__(name): + if name == 'HandleItem': + from ._generated.models import HandleItem + warnings.warn( + "HandleItem is deprecated and should not be used. Use Handle instead.", + DeprecationWarning + ) + return HandleItem + + raise AttributeError(f"module 'azure.storage.fileshare' has no attribute {name}") diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_deserialize.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_deserialize.py new file mode 100644 index 00000000..5db600d5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_deserialize.py @@ -0,0 +1,85 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# --------------------------------------------------------------------------_ +from typing import ( + Any, cast, Dict, List, Optional, Tuple, + TYPE_CHECKING +) + +from ._generated.models import ShareFileRangeList +from ._models import DirectoryProperties, FileProperties, ShareProperties +from ._shared.response_handlers import deserialize_metadata + +if TYPE_CHECKING: + from azure.core.pipeline import PipelineResponse + from ._shared.models import LocationMode + + +def deserialize_share_properties(response: "PipelineResponse", obj: Any, headers: Dict[str, Any]) -> ShareProperties: + metadata = deserialize_metadata(response, obj, headers) + share_properties = ShareProperties( + metadata=metadata, + **headers + ) + return share_properties + + +def deserialize_directory_properties( + response: "PipelineResponse", + obj: Any, + headers: Dict[str, Any] +) -> DirectoryProperties: + metadata = deserialize_metadata(response, obj, headers) + directory_properties = DirectoryProperties( + metadata=metadata, + **headers + ) + return directory_properties + + +def deserialize_file_properties(response: "PipelineResponse", obj: Any, headers: Dict[str, Any]) -> FileProperties: + metadata = deserialize_metadata(response, obj, headers) + file_properties = FileProperties( + metadata=metadata, + **headers + ) + if 'Content-Range' in headers: + if 'x-ms-content-md5' in headers: + file_properties.content_settings.content_md5 = headers['x-ms-content-md5'] + else: + file_properties.content_settings.content_md5 = None + return file_properties + + +def deserialize_file_stream( + response: "PipelineResponse", + obj: Any, + headers: Dict[str, Any] +) -> Tuple["LocationMode", Any]: + file_properties = deserialize_file_properties(response, obj, headers) + obj.properties = file_properties + return response.http_response.location_mode, obj + + +# Extracts out file permission +def deserialize_permission(response: "PipelineResponse", obj: Any, headers: Dict[str, Any]) -> Optional[str]: # pylint: disable=unused-argument + return cast(Optional[str], obj.permission) + + +# Extracts out file permission key +def deserialize_permission_key(response: "PipelineResponse", obj: Any, headers: Dict[str, Any]) -> Optional[str]: # pylint: disable=unused-argument + if response is None or headers is None: + return None + return cast(Optional[str], headers.get('x-ms-file-permission-key', None)) + + +def get_file_ranges_result(ranges: ShareFileRangeList) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]: + file_ranges = [] + clear_ranges = [] + if ranges.ranges: + file_ranges = [{'start': file_range.start, 'end': file_range.end} for file_range in ranges.ranges] + if ranges.clear_ranges: + clear_ranges = [{'start': clear_range.start, 'end': clear_range.end} for clear_range in ranges.clear_ranges] + return file_ranges, clear_ranges diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_directory_client.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_directory_client.py new file mode 100644 index 00000000..0d97031f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_directory_client.py @@ -0,0 +1,983 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=docstring-keyword-should-match-keyword-only + +import functools +import sys +import time +from datetime import datetime +from typing import ( + Any, AnyStr, cast, Dict, IO, Iterable, Optional, Union, + TYPE_CHECKING +) +from typing_extensions import Self + +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.core.paging import ItemPaged +from azure.core.pipeline import Pipeline +from azure.core.tracing.decorator import distributed_trace +from ._deserialize import deserialize_directory_properties +from ._directory_client_helpers import ( + _format_url, + _from_directory_url, + _parse_url +) +from ._file_client import ShareFileClient +from ._generated import AzureFileStorage +from ._models import DirectoryPropertiesPaged, Handle, HandlesPaged +from ._parser import _datetime_to_str, _get_file_permission, _parse_snapshot +from ._serialize import get_api_version, get_dest_access_conditions, get_rename_smb_properties +from ._shared.base_client import parse_connection_str, parse_query, StorageAccountHostsMixin, TransportWrapper +from ._shared.request_handlers import add_metadata_headers +from ._shared.response_handlers import process_storage_error, return_response_headers + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + +if TYPE_CHECKING: + from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential, TokenCredential + from ._models import DirectoryProperties, FileProperties, NTFSAttributes + + +class ShareDirectoryClient(StorageAccountHostsMixin): + """A client to interact with a specific directory, although it may not yet exist. + + For operations relating to a specific subdirectory or file in this share, the clients for those + entities can also be retrieved using the :func:`get_subdirectory_client` and :func:`get_file_client` functions. + + For more optional configuration, please click + `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #optional-configuration>`__. + + :param str account_url: + The URI to the storage account. In order to create a client given the full URI to the directory, + use the :func:`from_directory_url` classmethod. + :param share_name: + The name of the share for the directory. + :type share_name: str + :param str directory_path: + The directory path for the directory with which to interact. + If specified, this value will override a directory value specified in the directory URL. + :param str snapshot: + An optional share snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`ShareClient.create_snapshot`. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a TokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials.TokenCredential or + str or dict[str, str] or None + :keyword token_intent: + Required when using `TokenCredential` for authentication and ignored for other forms of authentication. + Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are: + + backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory + ACLs are bypassed and full permissions are granted. User must also have required RBAC permission. + + :paramtype token_intent: Literal['backup'] + :keyword bool allow_trailing_dot: If true, the trailing dot will not be trimmed from the target URI. + :keyword bool allow_source_trailing_dot: If true, the trailing dot will not be trimmed from the source URI. + :keyword str api_version: + The Storage API version to use for requests. Default value is the most recent service version that is + compatible with the current SDK. Setting to an older version may result in reduced feature compatibility. + + .. versionadded:: 12.1.0 + + :keyword str secondary_hostname: + The hostname of the secondary endpoint. + :keyword int max_range_size: The maximum range size used for a file upload. Defaults to 4*1024*1024. + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.file.core.windows.net. + """ + def __init__( + self, account_url: str, + share_name: str, + directory_path: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long + *, + token_intent: Optional[Literal['backup']] = None, + **kwargs: Any + ) -> None: + if hasattr(credential, 'get_token') and not token_intent: + raise ValueError("'token_intent' keyword is required when 'credential' is an TokenCredential.") + parsed_url = _parse_url(account_url, share_name) + path_snapshot, sas_token = parse_query(parsed_url.query) + if not sas_token and not credential: + raise ValueError( + 'You need to provide either an account shared key or SAS token when creating a storage service.') + self.snapshot = _parse_snapshot(snapshot, path_snapshot) + self.share_name = share_name + self.directory_path = directory_path + + self._query_str, credential = self._format_query_string( + sas_token, credential, share_snapshot=self.snapshot) + super(ShareDirectoryClient, self).__init__( + parsed_url, service='file-share', credential=credential, **kwargs) + self.allow_trailing_dot = kwargs.pop('allow_trailing_dot', None) + self.allow_source_trailing_dot = kwargs.pop('allow_source_trailing_dot', None) + self.file_request_intent = token_intent + self._client = AzureFileStorage(url=self.url, base_url=self.url, pipeline=self._pipeline, + allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, + file_request_intent=self.file_request_intent) + self._client._config.version = get_api_version(kwargs) # type: ignore [assignment] + + @classmethod + def from_directory_url( + cls, directory_url: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """Create a ShareDirectoryClient from a directory url. + + :param str directory_url: + The full URI to the directory. + :param str snapshot: + An optional share snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`ShareClient.create_snapshot`. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a TokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials.TokenCredential or + str or dict[str, str] or None + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.file.core.windows.net. + :returns: A directory client. + :rtype: ~azure.storage.fileshare.ShareDirectoryClient + """ + account_url, share_name, directory_path, snapshot = _from_directory_url(directory_url, snapshot) + return cls( + account_url=account_url, share_name=share_name, directory_path=directory_path, + snapshot=snapshot, credential=credential, **kwargs) + + def _format_url(self, hostname: str) -> str: + """Format the endpoint URL according to the current location mode hostname. + + :param str hostname: + The hostname of the current location mode. + :returns: A formatted endpoint URL including the current location mode hostname. + :rtype: str + """ + return _format_url(self.scheme, hostname, self.share_name, self.directory_path, self._query_str) + + @classmethod + def from_connection_string( + cls, conn_str: str, + share_name: str, + directory_path: str, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """Create ShareDirectoryClient from a Connection String. + + :param str conn_str: + A connection string to an Azure Storage account. + :param share_name: The name of the share. + :type share_name: str + :param str directory_path: + The directory path. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a TokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + Optional[Union[str, dict[str, str], AzureNamedKeyCredential, AzureSasCredential, "TokenCredential"]] + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.file.core.windows.net. + :returns: A directory client. + :rtype: ~azure.storage.fileshare.ShareDirectoryClient + """ + account_url, secondary, credential = parse_connection_str(conn_str, credential, 'file') + if 'secondary_hostname' not in kwargs: + kwargs['secondary_hostname'] = secondary + return cls( + account_url, share_name=share_name, directory_path=directory_path, credential=credential, **kwargs) + + def get_file_client(self, file_name: str, **kwargs: Any) -> ShareFileClient: + """Get a client to interact with a specific file. + + The file need not already exist. + + :param str file_name: The name of the file. + :returns: A File Client. + :rtype: ~azure.storage.fileshare.ShareFileClient + """ + if self.directory_path: + file_name = self.directory_path.rstrip('/') + "/" + file_name + + _pipeline = Pipeline( + transport=TransportWrapper(self._pipeline._transport), # pylint: disable=protected-access + policies=self._pipeline._impl_policies # pylint: disable=protected-access + ) + return ShareFileClient( + self.url, file_path=file_name, share_name=self.share_name, snapshot=self.snapshot, + credential=self.credential, token_intent=self.file_request_intent, api_version=self.api_version, + _hosts=self._hosts, _configuration=self._config, + _pipeline=_pipeline, _location_mode=self._location_mode, + allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, **kwargs) + + def get_subdirectory_client(self, directory_name: str, **kwargs: Any) -> "ShareDirectoryClient": + """Get a client to interact with a specific subdirectory. + + The subdirectory need not already exist. + + :param str directory_name: + The name of the subdirectory. + :returns: A Directory Client. + :rtype: ~azure.storage.fileshare.ShareDirectoryClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory.py + :start-after: [START get_subdirectory_client] + :end-before: [END get_subdirectory_client] + :language: python + :dedent: 12 + :caption: Gets the subdirectory client. + """ + directory_path = directory_name + if self.directory_path: + directory_path = self.directory_path.rstrip('/') + "/" + directory_name + + _pipeline = Pipeline( + transport=TransportWrapper(self._pipeline._transport), # pylint: disable=protected-access + policies=self._pipeline._impl_policies # pylint: disable=protected-access + ) + return ShareDirectoryClient( + self.url, share_name=self.share_name, directory_path=directory_path, snapshot=self.snapshot, + credential=self.credential, token_intent=self.file_request_intent, api_version=self.api_version, + _hosts=self._hosts, _configuration=self._config, _pipeline=_pipeline, + _location_mode=self._location_mode, allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, **kwargs) + + @distributed_trace + def create_directory(self, **kwargs: Any) -> Dict[str, Any]: + """Creates a new directory under the directory referenced by the client. + + :keyword file_attributes: + The file system attributes for files and directories. + If not set, the default value would be "none" and the attributes will be set to "Archive". + Here is an example for when the var type is str: 'Temporary|Archive'. + file_attributes value is not case sensitive. + :paramtype file_attributes: str or ~azure.storage.fileshare.NTFSAttributes or None + :keyword file_creation_time: Creation time for the directory. + :paramtype file_creation_time: str or ~datetime.datetime or None + :keyword file_last_write_time: Last write time for the directory. + :paramtype file_last_write_time: str or ~datetime.datetime or None + :keyword str file_permission: + If specified the permission (security descriptor) shall be set + for the directory/file. This header can be used if Permission size is + <= 8KB, else file-permission-key header shall be used. + Default value: Inherit. If SDDL is specified as input, it must have owner, group and dacl. + Note: Only one of the file-permission or file-permission-key should be specified. + :keyword str file_permission_key: + Key of the permission to be set for the directory/file. + Note: Only one of the file-permission or file-permission-key should be specified. + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_change_time: + Change time for the directory. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword metadata: + Name-value pairs associated with the directory as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword str owner: + NFS only. The owner of the directory. + :keyword str group: + NFS only. The owning group of the directory. + :keyword str file_mode: + NFS only. The file mode of the directory. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: Directory-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory.py + :start-after: [START create_directory] + :end-before: [END create_directory] + :language: python + :dedent: 12 + :caption: Creates a directory. + """ + timeout = kwargs.pop('timeout', None) + metadata = kwargs.pop('metadata', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + + file_attributes = kwargs.pop('file_attributes', None) + file_creation_time = kwargs.pop('file_creation_time', None) + file_last_write_time = kwargs.pop('file_last_write_time', None) + file_change_time = kwargs.pop('file_change_time', None) + file_permission = kwargs.pop('file_permission', None) + file_permission_key = kwargs.pop('file_permission_key', None) + file_permission = _get_file_permission(file_permission, file_permission_key, None) + + try: + return cast(Dict[str, Any], self._client.directory.create( + file_attributes=str(file_attributes) if file_attributes is not None else file_attributes, + file_creation_time=_datetime_to_str(file_creation_time), + file_last_write_time=_datetime_to_str(file_last_write_time), + file_change_time=_datetime_to_str(file_change_time), + file_permission=file_permission, + file_permission_key=file_permission_key, + timeout=timeout, + cls=return_response_headers, + headers=headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def delete_directory(self, **kwargs: Any) -> None: + """Marks the directory for deletion. The directory is + later deleted during garbage collection. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory.py + :start-after: [START delete_directory] + :end-before: [END delete_directory] + :language: python + :dedent: 12 + :caption: Deletes a directory. + """ + timeout = kwargs.pop('timeout', None) + try: + self._client.directory.delete(timeout=timeout, **kwargs) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def rename_directory(self, new_name: str, **kwargs: Any) -> "ShareDirectoryClient": + """ + Rename the source directory. + + :param str new_name: + The new directory name. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword bool overwrite: + A boolean value for if the destination file already exists, whether this request will + overwrite the file or not. If true, the rename will succeed and will overwrite the + destination file. If not provided or if false and the destination file does exist, the + request will not overwrite the destination file. If provided and the destination file + doesn't exist, the rename will succeed. + :keyword bool ignore_read_only: + A boolean value that specifies whether the ReadOnly attribute on a preexisting destination + file should be respected. If true, the rename will succeed, otherwise, a previous file at the + destination with the ReadOnly attribute set will cause the rename to fail. + :keyword str file_permission: + If specified the permission (security descriptor) shall be set for the directory. This header + can be used if Permission size is <= 8KB, else file_permission_key shall be used. + If SDDL is specified as input, it must have owner, group and dacl. + A value of 'preserve' can be passed to preserve source permissions. + Note: Only one of the file_permission or file_permission_key should be specified. + :keyword str file_permission_key: + Key of the permission to be set for the directory. + Note: Only one of the file-permission or file-permission-key should be specified. + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_attributes: + The file system attributes for the directory. + :paramtype file_attributes: ~azure.storage.fileshare.NTFSAttributes or str + :keyword file_creation_time: + Creation time for the directory. + :paramtype file_creation_time: ~datetime.datetime or str + :keyword file_last_write_time: + Last write time for the file. + :paramtype file_last_write_time: ~datetime.datetime or str + :keyword file_change_time: + Change time for the directory. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword Dict[str,str] metadata: + A name-value pair to associate with a file storage object. + :keyword destination_lease: + Required if the destination file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + :paramtype destination_lease: ~azure.storage.fileshare.ShareLeaseClient or str + :returns: The new Directory Client. + :rtype: ~azure.storage.fileshare.ShareDirectoryClient + """ + if not new_name: + raise ValueError("Please specify a new directory name.") + + new_name = new_name.strip('/') + new_path_and_query = new_name.split('?') + new_dir_path = new_path_and_query[0] + if len(new_path_and_query) == 2: + new_dir_sas = new_path_and_query[1] or self._query_str.strip('?') + else: + new_dir_sas = self._query_str.strip('?') + + new_directory_client = ShareDirectoryClient( + f'{self.scheme}://{self.primary_hostname}', self.share_name, new_dir_path, + credential=new_dir_sas or self.credential, api_version=self.api_version, + _hosts=self._hosts, _configuration=self._config, _pipeline=self._pipeline, + _location_mode=self._location_mode, allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, token_intent=self.file_request_intent + ) + + kwargs.update(get_rename_smb_properties(kwargs)) + + timeout = kwargs.pop('timeout', None) + overwrite = kwargs.pop('overwrite', None) + metadata = kwargs.pop('metadata', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + + destination_access_conditions = get_dest_access_conditions(kwargs.pop('destination_lease', None)) + + try: + new_directory_client._client.directory.rename( # pylint: disable=protected-access + self.url, + timeout=timeout, + replace_if_exists=overwrite, + destination_lease_access_conditions=destination_access_conditions, + headers=headers, + **kwargs) + + return new_directory_client + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def list_directories_and_files( + self, + name_starts_with: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged[Union["DirectoryProperties", "FileProperties"]]: + """Lists all the directories and files under the directory. + + :param str name_starts_with: + Filters the results to return only entities whose names + begin with the specified prefix. + :keyword List[str] include: + Include this parameter to specify one or more datasets to include in the response. + Possible str values are "timestamps", "Etag", "Attributes", "PermissionKey". + + .. versionadded:: 12.6.0 + + This keyword argument was introduced in API version '2020-10-02'. + + :keyword bool include_extended_info: + If this is set to true, file id will be returned in listed results. + + .. versionadded:: 12.6.0 + + This keyword argument was introduced in API version '2020-10-02'. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: An auto-paging iterable of dict-like DirectoryProperties and FileProperties + :rtype: ~azure.core.paging.ItemPaged[Union[DirectoryProperties, FileProperties]] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory.py + :start-after: [START lists_directory] + :end-before: [END lists_directory] + :language: python + :dedent: 12 + :caption: List directories and files. + """ + timeout = kwargs.pop('timeout', None) + results_per_page = kwargs.pop('results_per_page', None) + command = functools.partial( + self._client.directory.list_files_and_directories_segment, + sharesnapshot=self.snapshot, + timeout=timeout, + **kwargs) + return ItemPaged( + command, prefix=name_starts_with, results_per_page=results_per_page, + page_iterator_class=DirectoryPropertiesPaged) + + @distributed_trace + def list_handles(self, recursive: bool = False, **kwargs: Any) -> ItemPaged[Handle]: + """Lists opened handles on a directory or a file under the directory. + + :param bool recursive: + Boolean that specifies if operation should apply to the directory specified by the client, + its files, its subdirectories and their files. Default value is False. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: An auto-paging iterable of Handle + :rtype: ~azure.core.paging.ItemPaged[~azure.storage.fileshare.Handle] + """ + timeout = kwargs.pop('timeout', None) + results_per_page = kwargs.pop('results_per_page', None) + command = functools.partial( + self._client.directory.list_handles, + sharesnapshot=self.snapshot, + timeout=timeout, + recursive=recursive, + **kwargs) + return ItemPaged( + command, results_per_page=results_per_page, + page_iterator_class=HandlesPaged) + + @distributed_trace + def close_handle(self, handle: Union[str, Handle], **kwargs: Any) -> Dict[str, int]: + """Close an open file handle. + + :param handle: + A specific handle to close. + :type handle: str or ~azure.storage.fileshare.Handle + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: + The number of handles closed (this may be 0 if the specified handle was not found) + and the number of handles failed to close in a dict. + :rtype: dict[str, int] + """ + if isinstance(handle, Handle): + handle_id = handle.id + else: + handle_id = handle + if handle_id == '*': + raise ValueError("Handle ID '*' is not supported. Use 'close_all_handles' instead.") + try: + response = self._client.directory.force_close_handles( + handle_id, + marker=None, + recursive=None, + sharesnapshot=self.snapshot, + cls=return_response_headers, + **kwargs + ) + return { + 'closed_handles_count': response.get('number_of_handles_closed', 0), + 'failed_handles_count': response.get('number_of_handles_failed', 0) + } + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def close_all_handles(self, recursive: bool = False, **kwargs: Any) -> Dict[str, int]: + """Close any open file handles. + + This operation will block until the service has closed all open handles. + + :param bool recursive: + Boolean that specifies if operation should apply to the directory specified by the client, + its files, its subdirectories and their files. Default value is False. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: The number of handles closed (this may be 0 if the specified handle was not found) + and the number of handles failed to close in a dict. + :rtype: dict[str, int] + """ + timeout = kwargs.pop('timeout', None) + start_time = time.time() + + try_close = True + continuation_token = None + total_closed = 0 + total_failed = 0 + while try_close: + try: + response = self._client.directory.force_close_handles( + handle_id='*', + timeout=timeout, + marker=continuation_token, + recursive=recursive, + sharesnapshot=self.snapshot, + cls=return_response_headers, + **kwargs + ) + except HttpResponseError as error: + process_storage_error(error) + continuation_token = response.get('marker') + try_close = bool(continuation_token) + total_closed += response.get('number_of_handles_closed', 0) + total_failed += response.get('number_of_handles_failed', 0) + if timeout: + timeout = max(0, timeout - (time.time() - start_time)) + return { + 'closed_handles_count': total_closed, + 'failed_handles_count': total_failed + } + + @distributed_trace + def get_directory_properties(self, **kwargs: Any) -> "DirectoryProperties": + """Returns all user-defined metadata and system properties for the + specified directory. The data returned does not include the directory's + list of files. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: DirectoryProperties + :rtype: ~azure.storage.fileshare.DirectoryProperties + """ + timeout = kwargs.pop('timeout', None) + try: + response = cast("DirectoryProperties", self._client.directory.get_properties( + timeout=timeout, + cls=deserialize_directory_properties, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + return response + + @distributed_trace + def set_directory_metadata(self, metadata: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]: + """Sets the metadata for the directory. + + Each call to this operation replaces all existing metadata + attached to the directory. To remove all metadata from the directory, + call this operation with an empty metadata dict. + + :param metadata: + Name-value pairs associated with the directory as metadata. + :type metadata: dict[str, str] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: Directory-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + """ + timeout = kwargs.pop('timeout', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + try: + return cast(Dict[str, Any], self._client.directory.set_metadata( + timeout=timeout, + cls=return_response_headers, + headers=headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def exists(self, **kwargs: Any) -> bool: + """ + Returns True if a directory exists and returns False otherwise. + + :kwarg int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: True if the directory exists, False otherwise. + :rtype: bool + """ + try: + self._client.directory.get_properties(**kwargs) + return True + except HttpResponseError as error: + try: + process_storage_error(error) + except ResourceNotFoundError: + return False + + @distributed_trace + def set_http_headers( + self, file_attributes: Optional[Union[str, "NTFSAttributes"]] = None, + file_creation_time: Optional[Union[str, datetime]] = None, + file_last_write_time: Optional[Union[str, datetime]] = None, + file_permission: Optional[str] = None, + permission_key: Optional[str] = None, + **kwargs: Any + ) -> Dict[str, Any]: + """Sets HTTP headers on the directory. + + :param file_attributes: + The file system attributes for files and directories. + If not set, indicates preservation of existing values. + Here is an example for when the var type is str: 'Temporary|Archive' + :type file_attributes: str or ~azure.storage.fileshare.NTFSAttributes or None + :param file_creation_time: Creation time for the file + :type file_creation_time: str or ~datetime.datetime or None + :param file_last_write_time: Last write time for the file + :type file_last_write_time: str or ~datetime.datetime or None + :param file_permission: If specified the permission (security + descriptor) shall be set for the directory/file. This header can be + used if Permission size is <= 8KB, else x-ms-file-permission-key + header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the + x-ms-file-permission or x-ms-file-permission-key should be specified. + :type file_permission: str + :param permission_key: Key of the permission to be set for the + directory/file. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. + :type permission_key: str + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_change_time: + Change time for the directory. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword str owner: + NFS only. The owner of the directory. + :keyword str group: + NFS only. The owning group of the directory. + :keyword str file_mode: + NFS only. The file mode of the directory. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + """ + timeout = kwargs.pop('timeout', None) + file_permission = _get_file_permission(file_permission, permission_key, None) + file_change_time = kwargs.pop('file_change_time', None) + try: + return cast(Dict[str, Any], self._client.directory.set_properties( + file_attributes=str(file_attributes) if file_attributes is not None else file_attributes, + file_creation_time=_datetime_to_str(file_creation_time), + file_last_write_time=_datetime_to_str(file_last_write_time), + file_change_time=_datetime_to_str(file_change_time), + file_permission=file_permission, + file_permission_key=permission_key, + timeout=timeout, + cls=return_response_headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def create_subdirectory(self, directory_name: str, **kwargs: Any) -> "ShareDirectoryClient": + """Creates a new subdirectory and returns a client to interact + with the subdirectory. + + :param str directory_name: + The name of the subdirectory. + :keyword metadata: + Name-value pairs associated with the subdirectory as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: ShareDirectoryClient + :rtype: ~azure.storage.fileshare.ShareDirectoryClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory.py + :start-after: [START create_subdirectory] + :end-before: [END create_subdirectory] + :language: python + :dedent: 12 + :caption: Create a subdirectory. + """ + metadata = kwargs.pop('metadata', None) + timeout = kwargs.pop('timeout', None) + subdir = self.get_subdirectory_client(directory_name) + subdir.create_directory(metadata=metadata, timeout=timeout, **kwargs) + return subdir + + @distributed_trace + def delete_subdirectory(self, directory_name: str, **kwargs: Any) -> None: + """Deletes a subdirectory. + + :param str directory_name: + The name of the subdirectory. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory.py + :start-after: [START delete_subdirectory] + :end-before: [END delete_subdirectory] + :language: python + :dedent: 12 + :caption: Delete a subdirectory. + """ + timeout = kwargs.pop('timeout', None) + subdir = self.get_subdirectory_client(directory_name) + subdir.delete_directory(timeout=timeout, **kwargs) + + @distributed_trace + def upload_file( + self, file_name: str, + data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]], + length: Optional[int] = None, + **kwargs: Any + ) -> ShareFileClient: + """Creates a new file in the directory and returns a ShareFileClient + to interact with the file. + + :param str file_name: + The name of the file. + :param data: + Content of the file. + :type data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]] + :param int length: + Length of the file in bytes. Specify its maximum size, up to 1 TiB. + :keyword metadata: + Name-value pairs associated with the file as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword ~azure.storage.fileshare.ContentSettings content_settings: + ContentSettings object used to set file properties. Used to set content type, encoding, + language, disposition, md5, and cache control. + :keyword bool validate_content: + If true, calculates an MD5 hash for each range of the file. The storage + service checks the hash of the content that has arrived with the hash + that was sent. This is primarily valuable for detecting bitflips on + the wire if using http instead of https as https (the default) will + already validate. Note that this MD5 hash is not stored with the + file. + :keyword int max_concurrency: + Maximum number of parallel connections to use. + :keyword progress_hook: + A callback to track the progress of a long running upload. The signature is + function(current: int, total: Optional[int]) where current is the number of bytes transferred + so far, and total is the size of the blob or None if the size is unknown. + :paramtype progress_hook: Callable[[int, Optional[int]], None] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword str encoding: + Defaults to UTF-8. + :returns: ShareFileClient + :rtype: ~azure.storage.fileshare.ShareFileClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory.py + :start-after: [START upload_file_to_directory] + :end-before: [END upload_file_to_directory] + :language: python + :dedent: 12 + :caption: Upload a file to a directory. + """ + file_client = self.get_file_client(file_name) + file_client.upload_file( + data, + length=length, + **kwargs) + return file_client + + @distributed_trace + def delete_file(self, file_name: str, **kwargs: Any) -> None: + """Marks the specified file for deletion. The file is later + deleted during garbage collection. + + :param str file_name: + The name of the file to delete. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory.py + :start-after: [START delete_file_in_directory] + :end-before: [END delete_file_in_directory] + :language: python + :dedent: 12 + :caption: Delete a file in a directory. + """ + file_client = self.get_file_client(file_name) + file_client.delete_file(**kwargs) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_directory_client_helpers.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_directory_client_helpers.py new file mode 100644 index 00000000..cf37c24f --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_directory_client_helpers.py @@ -0,0 +1,61 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from typing import ( + Any, Dict, Optional, Tuple, Union, + TYPE_CHECKING +) +from urllib.parse import quote, unquote, urlparse + +from ._shared.base_client import parse_query + +if TYPE_CHECKING: + from urllib.parse import ParseResult + + +def _parse_url(account_url: str, share_name: str) -> "ParseResult": + try: + if not account_url.lower().startswith('http'): + account_url = "https://" + account_url + except AttributeError as exc: + raise ValueError("Account URL must be a string.") from exc + parsed_url = urlparse(account_url.rstrip('/')) + if not share_name: + raise ValueError("Please specify a share name.") + if not parsed_url.netloc: + raise ValueError(f"Invalid URL: {account_url}") + return parsed_url + + +def _format_url(scheme: str, hostname: str, share_name: Union[str, bytes], dir_path: str, query_str: str) -> str: + if isinstance(share_name, str): + share_name = share_name.encode('UTF-8') + directory_path = "" + if dir_path: + directory_path = "/" + quote(dir_path, safe='~') + return f"{scheme}://{hostname}/{quote(share_name)}{directory_path}{query_str}" + + +def _from_directory_url( + directory_url: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None +) -> Tuple[str, str, str, Optional[Union[str, Dict[str, Any]]]]: + try: + if not directory_url.lower().startswith('http'): + directory_url = "https://" + directory_url + except AttributeError as exc: + raise ValueError("Directory URL must be a string.") from exc + parsed_url = urlparse(directory_url.rstrip('/')) + if not parsed_url.path and not parsed_url.netloc: + raise ValueError(f"Invalid URL: {directory_url}") + account_url = parsed_url.netloc.rstrip('/') + "?" + parsed_url.query + path_snapshot, _ = parse_query(parsed_url.query) + + share_name, _, path_dir = parsed_url.path.lstrip('/').partition('/') + share_name = unquote(share_name) + snapshot = snapshot or path_snapshot + + return account_url, share_name, path_dir, snapshot diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_download.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_download.py new file mode 100644 index 00000000..a37bca9a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_download.py @@ -0,0 +1,524 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import sys +import threading +import warnings +from io import BytesIO +from typing import ( + Any, Callable, Generator, IO, Iterator, Optional, Tuple, + TYPE_CHECKING +) + +from azure.core.exceptions import HttpResponseError, ResourceModifiedError +from azure.core.tracing.common import with_current_context +from ._shared.request_handlers import validate_and_format_range_headers +from ._shared.response_handlers import parse_length_from_content_range, process_storage_error + +if TYPE_CHECKING: + from ._generated.operations import FileOperations + from ._models import FileProperties + from ._shared.models import StorageConfiguration + + +def process_content(data: Any) -> bytes: + if data is None: + raise ValueError("Response cannot be None.") + + try: + return b"".join(list(data)) + except Exception as error: + raise HttpResponseError(message="Download stream interrupted.", response=data.response, error=error) from error + + +class _ChunkDownloader(object): # pylint: disable=too-many-instance-attributes + def __init__( + self, client: "FileOperations", + total_size: int, + chunk_size: int, + current_progress: int, + start_range: int, + end_range: int, + validate_content: bool, + etag: str, + stream: Any = None, + parallel: Optional[int] = None, + progress_hook: Optional[Callable[[int, Optional[int]], None]] = None, + **kwargs: Any + ) -> None: + self.client = client + self.etag = etag + # Information on the download range/chunk size + self.chunk_size = chunk_size + self.total_size = total_size + self.start_index = start_range + self.end_index = end_range + + # The destination that we will write to + self.stream = stream + self.stream_lock = threading.Lock() if parallel else None + self.progress_lock = threading.Lock() if parallel else None + self.progress_hook = progress_hook + + # For a parallel download, the stream is always seekable, so we note down the current position + # in order to seek to the right place when out-of-order chunks come in + self.stream_start = stream.tell() if parallel else 0 + + # Download progress so far + self.progress_total = current_progress + + # Parameters for each get operation + self.validate_content = validate_content + self.request_options = kwargs + + def _calculate_range(self, chunk_start: int) -> Tuple[int, int]: + if chunk_start + self.chunk_size > self.end_index: + chunk_end = self.end_index + else: + chunk_end = chunk_start + self.chunk_size + return chunk_start, chunk_end + + def get_chunk_offsets(self) -> Generator[int, None, None]: + index = self.start_index + while index < self.end_index: + yield index + index += self.chunk_size + + def process_chunk(self, chunk_start: int) -> None: + chunk_start, chunk_end = self._calculate_range(chunk_start) + chunk_data = self._download_chunk(chunk_start, chunk_end - 1) + length = chunk_end - chunk_start + if length > 0: + self._write_to_stream(chunk_data, chunk_start) + self._update_progress(length) + + def yield_chunk(self, chunk_start: int) -> bytes: + chunk_start, chunk_end = self._calculate_range(chunk_start) + return self._download_chunk(chunk_start, chunk_end - 1) + + def _update_progress(self, length: int) -> None: + if self.progress_lock: + with self.progress_lock: # pylint: disable=not-context-manager + self.progress_total += length + else: + self.progress_total += length + + if self.progress_hook: + self.progress_hook(self.progress_total, self.total_size) + + def _write_to_stream(self, chunk_data: bytes, chunk_start: int) -> None: + if self.stream_lock: + with self.stream_lock: # pylint: disable=not-context-manager + self.stream.seek(self.stream_start + (chunk_start - self.start_index)) + self.stream.write(chunk_data) + else: + self.stream.write(chunk_data) + + def _download_chunk(self, chunk_start: int, chunk_end: int) -> bytes: + range_header, range_validation = validate_and_format_range_headers( + chunk_start, chunk_end, check_content_md5=self.validate_content + ) + + try: + response: Any = None + _, response = self.client.download( + range=range_header, + range_get_content_md5=range_validation, + validate_content=self.validate_content, + data_stream_total=self.total_size, + download_stream_current=self.progress_total, + **self.request_options + ) + if response.properties.etag != self.etag: + raise ResourceModifiedError(message="The file has been modified while downloading.") + + except HttpResponseError as error: + process_storage_error(error) + + chunk_data = process_content(response) + return chunk_data + + +class _ChunkIterator(object): + """Iterator for chunks in file download stream.""" + + def __init__(self, size: int, content: bytes, downloader: Optional[_ChunkDownloader], chunk_size: int) -> None: + self.size = size + self._chunk_size = chunk_size + self._current_content = content + self._iter_downloader = downloader + self._iter_chunks: Optional[Generator[int, None, None]] = None + self._complete = size == 0 + + def __len__(self) -> int: + return self.size + + def __iter__(self) -> Iterator[bytes]: + return self + + def __next__(self) -> bytes: + if self._complete: + raise StopIteration("Download complete") + if not self._iter_downloader: + # cut the data obtained from initial GET into chunks + if len(self._current_content) > self._chunk_size: + return self._get_chunk_data() + self._complete = True + return self._current_content + + if not self._iter_chunks: + self._iter_chunks = self._iter_downloader.get_chunk_offsets() + + # initial GET result still has more than _chunk_size bytes of data + if len(self._current_content) >= self._chunk_size: + return self._get_chunk_data() + + try: + chunk = next(self._iter_chunks) + self._current_content += self._iter_downloader.yield_chunk(chunk) + except StopIteration as e: + self._complete = True + if self._current_content: + return self._current_content + raise e + + return self._get_chunk_data() + + next = __next__ # Python 2 compatibility. + + def _get_chunk_data(self) -> bytes: + chunk_data = self._current_content[: self._chunk_size] + self._current_content = self._current_content[self._chunk_size:] + return chunk_data + + +class StorageStreamDownloader(object): # pylint: disable=too-many-instance-attributes + """A streaming object to download from Azure Storage.""" + + name: str + """The name of the file being downloaded.""" + path: str + """The full path of the file.""" + share: str + """The name of the share where the file is.""" + properties: "FileProperties" + """The properties of the file being downloaded. If only a range of the data is being + downloaded, this will be reflected in the properties.""" + size: int + """The size of the total data in the stream. This will be the byte range if specified, + otherwise the total size of the file.""" + + def __init__( + self, client: "FileOperations" = None, # type: ignore [assignment] + config: "StorageConfiguration" = None, # type: ignore [assignment] + start_range: Optional[int] = None, + end_range: Optional[int] = None, + validate_content: bool = None, # type: ignore [assignment] + max_concurrency: int = 1, + name: str = None, # type: ignore [assignment] + path: str = None, # type: ignore [assignment] + share: str = None, # type: ignore [assignment] + encoding: Optional[str] = None, + **kwargs: Any + ) -> None: + self.name = name + self.path = path + self.share = share + self.size = 0 + + self._client = client + self._config = config + self._start_range = start_range + self._end_range = end_range + self._max_concurrency = max_concurrency + self._encoding = encoding + self._validate_content = validate_content + self._progress_hook = kwargs.pop('progress_hook', None) + self._request_options = kwargs + self._location_mode = None + self._download_complete = False + self._current_content = b"" + self._file_size = 0 + self._response = None + self._etag = "" + + # The service only provides transactional MD5s for chunks under 4MB. + # If validate_content is on, get only self.MAX_CHUNK_GET_SIZE for the first + # chunk so a transactional MD5 can be retrieved. + self._first_get_size = ( + self._config.max_single_get_size if not self._validate_content else self._config.max_chunk_get_size + ) + initial_request_start = self._start_range or 0 + if self._end_range is not None and self._end_range - initial_request_start < self._first_get_size: + initial_request_end = self._end_range + else: + initial_request_end = initial_request_start + self._first_get_size - 1 + + self._initial_range = (initial_request_start, initial_request_end) + + self._response = self._initial_request() + self.properties = self._response.properties + self.properties.name = self.name + self.properties.path = self.path + self.properties.share = self.share + + # Set the content length to the download size instead of the size of + # the last range + self.properties.size = self.size + + # Overwrite the content range to the user requested range + self.properties.content_range = f"bytes {self._start_range}-{self._end_range}/{self._file_size}" + + # Overwrite the content MD5 as it is the MD5 for the last range instead + # of the stored MD5 + # TODO: Set to the stored MD5 when the service returns this + self.properties.content_md5 = None # type: ignore [attr-defined] + + if self.size == 0: + self._current_content = b"" + else: + self._current_content = process_content(self._response) + + def __len__(self) -> int: + return self.size + + def _initial_request(self): + range_header, range_validation = validate_and_format_range_headers( + self._initial_range[0], + self._initial_range[1], + start_range_required=False, + end_range_required=False, + check_content_md5=self._validate_content + ) + + try: + location_mode, response = self._client.download( + range=range_header, + range_get_content_md5=range_validation, + validate_content=self._validate_content, + data_stream_total=None, + download_stream_current=0, + **self._request_options + ) + + # Check the location we read from to ensure we use the same one + # for subsequent requests. + self._location_mode = location_mode + + # Parse the total file size and adjust the download size if ranges + # were specified + self._file_size = parse_length_from_content_range(response.properties.content_range) + if self._file_size is None: + raise ValueError("Required Content-Range response header is missing or malformed.") + + if self._end_range is not None: + # Use the end range index unless it is over the end of the file + self.size = min(self._file_size, self._end_range - self._start_range + 1) + elif self._start_range is not None: + self.size = self._file_size - self._start_range + else: + self.size = self._file_size + + except HttpResponseError as error: + if self._start_range is None and error.response and error.response.status_code == 416: + # Get range will fail on an empty file. If the user did not + # request a range, do a regular get request in order to get + # any properties. + try: + _, response = self._client.download( + validate_content=self._validate_content, + data_stream_total=0, + download_stream_current=0, + **self._request_options + ) + except HttpResponseError as e: + process_storage_error(e) + + # Set the download size to empty + self.size = 0 + self._file_size = 0 + else: + process_storage_error(error) + + # If the file is small, the download is complete at this point. + # If file size is large, download the rest of the file in chunks. + if response.properties.size == self.size: + self._download_complete = True + self._etag = response.properties.etag + return response + + def chunks(self) -> Iterator[bytes]: + """ + Iterate over chunks in the download stream. + + :return: An iterator of the chunks in the download stream. + :rtype: Iterator[bytes] + """ + if self.size == 0 or self._download_complete: + iter_downloader = None + else: + data_end = self._file_size + if self._end_range is not None: + # Use the end range index unless it is over the end of the file + data_end = min(self._file_size, self._end_range + 1) + iter_downloader = _ChunkDownloader( + client=self._client, + total_size=self.size, + chunk_size=self._config.max_chunk_get_size, + current_progress=self._first_get_size, + start_range=self._initial_range[1] + 1, # start where the first download ended + end_range=data_end, + stream=None, + parallel=False, + validate_content=self._validate_content, + use_location=self._location_mode, + etag=self._etag, + **self._request_options + ) + return _ChunkIterator( + size=self.size, + content=self._current_content, + downloader=iter_downloader, + chunk_size=self._config.max_chunk_get_size) + + def readall(self) -> bytes: + """Download the contents of this file. + + This operation is blocking until all data is downloaded. + :return: The entire blob content as bytes. + :rtype: bytes + """ + stream = BytesIO() + self.readinto(stream) + data = stream.getvalue() + if self._encoding: + return data.decode(self._encoding) # type: ignore [return-value] + return data + + def content_as_bytes(self, max_concurrency=1): + """DEPRECATED: Download the contents of this file. + + This operation is blocking until all data is downloaded. + + This method is deprecated, use func:`readall` instead. + + :param int max_concurrency: + The number of parallel connections with which to download. + :return: The contents of the file as bytes. + :rtype: bytes + """ + warnings.warn( + "content_as_bytes is deprecated, use readall instead", + DeprecationWarning + ) + self._max_concurrency = max_concurrency + return self.readall() + + def content_as_text(self, max_concurrency=1, encoding="UTF-8"): + """DEPRECATED: Download the contents of this file, and decode as text. + + This operation is blocking until all data is downloaded. + + This method is deprecated, use func:`readall` instead. + + :param int max_concurrency: + The number of parallel connections with which to download. + :param str encoding: + Test encoding to decode the downloaded bytes. Default is UTF-8. + :return: The contents of the file as a str. + :rtype: str + """ + warnings.warn( + "content_as_text is deprecated, use readall instead", + DeprecationWarning + ) + self._max_concurrency = max_concurrency + self._encoding = encoding + return self.readall() + + def readinto(self, stream: IO[bytes]) -> int: + """Download the contents of this file to a stream. + + :param IO[bytes] stream: + The stream to download to. This can be an open file-handle, + or any writable stream. The stream must be seekable if the download + uses more than one parallel connection. + :returns: The number of bytes read. + :rtype: int + """ + # The stream must be seekable if parallel download is required + parallel = self._max_concurrency > 1 + if parallel: + error_message = "Target stream handle must be seekable." + if sys.version_info >= (3,) and not stream.seekable(): + raise ValueError(error_message) + + try: + stream.seek(stream.tell()) + except (NotImplementedError, AttributeError) as exc: + raise ValueError(error_message) from exc + + # Write the content to the user stream + stream.write(self._current_content) + if self._progress_hook: + self._progress_hook(len(self._current_content), self.size) + + if self._download_complete: + return self.size + + data_end = self._file_size + if self._end_range is not None: + # Use the length unless it is over the end of the file + data_end = min(self._file_size, self._end_range + 1) + + downloader = _ChunkDownloader( + client=self._client, + total_size=self.size, + chunk_size=self._config.max_chunk_get_size, + current_progress=self._first_get_size, + start_range=self._initial_range[1] + 1, # Start where the first download ended + end_range=data_end, + stream=stream, + parallel=parallel, + validate_content=self._validate_content, + use_location=self._location_mode, + progress_hook=self._progress_hook, + etag=self._etag, + **self._request_options + ) + if parallel: + import concurrent.futures + with concurrent.futures.ThreadPoolExecutor(self._max_concurrency) as executor: + list(executor.map( + with_current_context(downloader.process_chunk), + downloader.get_chunk_offsets() + )) + else: + for chunk in downloader.get_chunk_offsets(): + downloader.process_chunk(chunk) + return self.size + + def download_to_stream(self, stream, max_concurrency=1): + """DEPRECATED: Download the contents of this file to a stream. + + This method is deprecated, use func:`readinto` instead. + + :param IO stream: + The stream to download to. This can be an open file-handle, + or any writable stream. The stream must be seekable if the download + uses more than one parallel connection. + :param int max_concurrency: + The number of parallel connections with which to download. + :returns: The properties of the downloaded file. + :rtype: Any + """ + warnings.warn( + "download_to_stream is deprecated, use readinto instead", + DeprecationWarning + ) + self._max_concurrency = max_concurrency + self.readinto(stream) + return self.properties diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_file_client.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_file_client.py new file mode 100644 index 00000000..e2fc4f11 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_file_client.py @@ -0,0 +1,1739 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=docstring-keyword-should-match-keyword-only, too-many-lines, too-many-public-methods + +import functools +import sys +import time +from datetime import datetime +from io import BytesIO +from typing import ( + Any, AnyStr, Callable, cast, Dict, IO, Iterable, List, Optional, Tuple, Union, + TYPE_CHECKING +) +from typing_extensions import Self + +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.core.paging import ItemPaged +from azure.core.tracing.decorator import distributed_trace +from ._deserialize import deserialize_file_properties, deserialize_file_stream, get_file_ranges_result +from ._download import StorageStreamDownloader +from ._file_client_helpers import ( + _format_url, + _from_file_url, + _get_ranges_options, + _parse_url, + _upload_range_from_url_options +) +from ._generated import AzureFileStorage +from ._generated.models import FileHTTPHeaders +from ._lease import ShareLeaseClient +from ._models import FileProperties, Handle, HandlesPaged +from ._parser import _datetime_to_str, _get_file_permission, _parse_snapshot +from ._serialize import ( + get_access_conditions, + get_api_version, + get_dest_access_conditions, + get_rename_smb_properties, + get_smb_properties, + get_source_access_conditions +) +from ._shared.base_client import StorageAccountHostsMixin, parse_connection_str, parse_query +from ._shared.request_handlers import add_metadata_headers, get_length +from ._shared.response_handlers import return_response_headers, process_storage_error +from ._shared.uploads import IterStreamer, FileChunkUploader, upload_data_chunks + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + +if TYPE_CHECKING: + from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential, TokenCredential + from ._models import ContentSettings, NTFSAttributes + from ._shared.base_client import StorageConfiguration + + +def _upload_file_helper( + client: "ShareFileClient", + stream: Any, + size: Optional[int], + metadata: Optional[Dict[str, str]], + content_settings: Optional["ContentSettings"], + validate_content: bool, + timeout: Optional[int], + max_concurrency: int, + file_settings: "StorageConfiguration", + file_attributes: Optional[Union[str, "NTFSAttributes"]] = None, + file_creation_time: Optional[Union[str, datetime]] = None, + file_last_write_time: Optional[Union[str, datetime]] = None, + file_permission: Optional[str] = None, + file_permission_key: Optional[str] = None, + progress_hook: Optional[Callable[[int, Optional[int]], None]] = None, + **kwargs: Any +) -> Dict[str, Any]: + try: + if size is None or size < 0: + raise ValueError("A content size must be specified for a File.") + response = client.create_file( + size, + content_settings=content_settings, + metadata=metadata, + timeout=timeout, + file_attributes=file_attributes, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + file_permission=file_permission, + permission_key=file_permission_key, + **kwargs + ) + if size == 0: + return response + + responses = upload_data_chunks( + service=client, + uploader_class=FileChunkUploader, + total_size=size, + chunk_size=file_settings.max_range_size, + stream=stream, + max_concurrency=max_concurrency, + validate_content=validate_content, + progress_hook=progress_hook, + timeout=timeout, + **kwargs + ) + return cast(Dict[str, Any], sorted(responses, key=lambda r: r.get('last_modified'))[-1]) + except HttpResponseError as error: + process_storage_error(error) + + +class ShareFileClient(StorageAccountHostsMixin): + """A client to interact with a specific file, although that file may not yet exist. + + For more optional configuration, please click + `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #optional-configuration>`__. + + :param str account_url: + The URI to the storage account. In order to create a client given the full URI to the + file, use the :func:`from_file_url` classmethod. + :param share_name: + The name of the share for the file. + :type share_name: str + :param str file_path: + The file path to the file with which to interact. If specified, this value will override + a file value specified in the file URL. + :param str snapshot: + An optional file snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`ShareClient.create_snapshot`. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a TokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials.TokenCredential or + str or dict[str, str] or None + :keyword token_intent: + Required when using `TokenCredential` for authentication and ignored for other forms of authentication. + Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are: + + backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory + ACLs are bypassed and full permissions are granted. User must also have required RBAC permission. + + :paramtype token_intent: Literal['backup'] + :keyword bool allow_trailing_dot: If true, the trailing dot will not be trimmed from the target URI. + :keyword bool allow_source_trailing_dot: If true, the trailing dot will not be trimmed from the source URI. + :keyword str api_version: + The Storage API version to use for requests. Default value is the most recent service version that is + compatible with the current SDK. Setting to an older version may result in reduced feature compatibility. + + .. versionadded:: 12.1.0 + + :keyword str secondary_hostname: + The hostname of the secondary endpoint. + :keyword int max_range_size: The maximum range size used for a file upload. Defaults to 4*1024*1024. + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.file.core.windows.net. + """ + def __init__( + self, account_url: str, + share_name: str, + file_path: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long + *, + token_intent: Optional[Literal['backup']] = None, + **kwargs: Any + ) -> None: + if hasattr(credential, 'get_token') and not token_intent: + raise ValueError("'token_intent' keyword is required when 'credential' is an TokenCredential.") + parsed_url = _parse_url(account_url, share_name, file_path) + path_snapshot, sas_token = parse_query(parsed_url.query) + if not sas_token and not credential: + raise ValueError( + 'You need to provide either an account shared key or SAS token when creating a storage service.') + self.snapshot = _parse_snapshot(snapshot, path_snapshot) + self.share_name = share_name + self.file_path = file_path.split('/') + self.file_name = self.file_path[-1] + self.directory_path = "/".join(self.file_path[:-1]) + + self._query_str, credential = self._format_query_string( + sas_token, credential, share_snapshot=self.snapshot) + super(ShareFileClient, self).__init__( + parsed_url, service='file-share', credential=credential, **kwargs) + self.allow_trailing_dot = kwargs.pop('allow_trailing_dot', None) + self.allow_source_trailing_dot = kwargs.pop('allow_source_trailing_dot', None) + self.file_request_intent = token_intent + self._client = AzureFileStorage(url=self.url, base_url=self.url, pipeline=self._pipeline, + allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, + file_request_intent=self.file_request_intent) + self._client._config.version = get_api_version(kwargs) # type: ignore [assignment] + + @classmethod + def from_file_url( + cls, file_url: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """A client to interact with a specific file, although that file may not yet exist. + + :param str file_url: The full URI to the file. + :param str snapshot: + An optional file snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`ShareClient.create_snapshot`. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a TokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials.TokenCredential or + str or dict[str, str] or None + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.file.core.windows.net. + :returns: A File client. + :rtype: ~azure.storage.fileshare.ShareFileClient + """ + account_url, share_name, file_path, snapshot = _from_file_url(file_url, snapshot) + return cls(account_url, share_name, file_path, snapshot, credential, **kwargs) + + def _format_url(self, hostname: str): + return _format_url(self.scheme, hostname, self.share_name, self.file_path, self._query_str) + + @classmethod + def from_connection_string( + cls, conn_str: str, + share_name: str, + file_path: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """Create ShareFileClient from a Connection String. + + :param str conn_str: + A connection string to an Azure Storage account. + :param share_name: The name of the share. + :type share_name: str + :param str file_path: + The file path. + :param str snapshot: + An optional file snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`ShareClient.create_snapshot`. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a TokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials.TokenCredential or + str or dict[str, str] or None + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type TokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.file.core.windows.net. + :returns: A File client. + :rtype: ~azure.storage.fileshare.ShareFileClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_hello_world.py + :start-after: [START create_file_client] + :end-before: [END create_file_client] + :language: python + :dedent: 12 + :caption: Creates the file client with connection string. + """ + account_url, secondary, credential = parse_connection_str(conn_str, credential, 'file') + if 'secondary_hostname' not in kwargs: + kwargs['secondary_hostname'] = secondary + return cls( + account_url, share_name=share_name, file_path=file_path, snapshot=snapshot, credential=credential, **kwargs) + + @distributed_trace + def acquire_lease(self, lease_id: Optional[str] = None, **kwargs: Any) -> ShareLeaseClient: + """Requests a new lease. + + If the file does not have an active lease, the File + Service creates a lease on the blob and returns a new lease. + + :param str lease_id: + Proposed lease ID, in a GUID string format. The File Service + returns 400 (Invalid request) if the proposed lease ID is not + in the correct format. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: A ShareLeaseClient object. + :rtype: ~azure.storage.fileshare.ShareLeaseClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_client.py + :start-after: [START acquire_and_release_lease_on_file] + :end-before: [END acquire_and_release_lease_on_file] + :language: python + :dedent: 12 + :caption: Acquiring a lease on a file. + """ + kwargs['lease_duration'] = -1 + lease = ShareLeaseClient(self, lease_id=lease_id) + lease.acquire(**kwargs) + return lease + + @distributed_trace + def exists(self, **kwargs: Any) -> bool: + """ + Returns True if the file exists and returns False otherwise. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: True if the file exists, False otherwise. + :rtype: bool + """ + try: + self._client.file.get_properties(**kwargs) + return True + except HttpResponseError as error: + try: + process_storage_error(error) + except ResourceNotFoundError: + return False + + @distributed_trace + def create_file( + self, size: int, + file_attributes: Optional[Union[str, "NTFSAttributes"]] = None, + file_creation_time: Optional[Union[str, datetime]] = None, + file_last_write_time: Optional[Union[str, datetime]] = None, + file_permission: Optional[str] = None, + permission_key: Optional[str] = None, + **kwargs: Any + ) -> Dict[str, Any]: + """Creates a new file. + + Note that it only initializes the file with no content. + + :param int size: Specifies the maximum size for the file, + up to 1 TB. + :param file_attributes: + The file system attributes for files and directories. + If not set, the default value would be "None" and the attributes will be set to "Archive". + Here is an example for when the var type is str: 'Temporary|Archive'. + file_attributes value is not case sensitive. + :type file_attributes: str or ~azure.storage.fileshare.NTFSAttributes or None + :param file_creation_time: Creation time for the file + Default value: Now. + :type file_creation_time: str or ~datetime.datetime or None + :param file_last_write_time: Last write time for the file + Default value: Now. + :type file_last_write_time: str or ~datetime.datetime or None + :param file_permission: If specified the permission (security + descriptor) shall be set for the directory/file. This header can be + used if Permission size is <= 8KB, else x-ms-file-permission-key + header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the + x-ms-file-permission or x-ms-file-permission-key should be specified. + :type file_permission: str + :param permission_key: Key of the permission to be set for the + directory/file. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. + :type permission_key: str + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_change_time: + Change time for the file. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword ~azure.storage.fileshare.ContentSettings content_settings: + ContentSettings object used to set file properties. Used to set content type, encoding, + language, disposition, md5, and cache control. + :keyword metadata: + Name-value pairs associated with the file as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword str owner: + NFS only. The owner of the file. + :keyword str group: + NFS only. The owning group of the file. + :keyword str file_mode: + NFS only. The file mode of the file. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_client.py + :start-after: [START create_file] + :end-before: [END create_file] + :language: python + :dedent: 12 + :caption: Create a file. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + content_settings = kwargs.pop('content_settings', None) + metadata = kwargs.pop('metadata', None) + timeout = kwargs.pop('timeout', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + file_http_headers = None + if content_settings: + file_http_headers = FileHTTPHeaders( + file_cache_control=content_settings.cache_control, + file_content_type=content_settings.content_type, + file_content_md5=bytearray(content_settings.content_md5) if content_settings.content_md5 else None, + file_content_encoding=content_settings.content_encoding, + file_content_language=content_settings.content_language, + file_content_disposition=content_settings.content_disposition + ) + file_permission = _get_file_permission(file_permission, permission_key, None) + file_change_time = kwargs.pop('file_change_time', None) + try: + return cast(Dict[str, Any], self._client.file.create( + file_content_length=size, + metadata=metadata, + file_attributes=str(file_attributes) if file_attributes is not None else file_attributes, + file_creation_time=_datetime_to_str(file_creation_time), + file_last_write_time=_datetime_to_str(file_last_write_time), + file_change_time=_datetime_to_str(file_change_time), + file_permission=file_permission, + file_permission_key=permission_key, + file_http_headers=file_http_headers, + lease_access_conditions=access_conditions, + headers=headers, + timeout=timeout, + cls=return_response_headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def upload_file( + self, data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]], + length: Optional[int] = None, + file_attributes: Optional[Union[str, "NTFSAttributes"]] = None, + file_creation_time: Optional[Union[str, datetime]] = None, + file_last_write_time: Optional[Union[str, datetime]] = None, + file_permission: Optional[str] = None, + permission_key: Optional[str] = None, + **kwargs + ) -> Dict[str, Any]: + """Uploads a new file. + + :param data: + Content of the file. + :type data: Union[bytes, str, Iterable[AnyStr], IO[AnyStr]] + :param int length: + Length of the file in bytes. Specify its maximum size, up to 1 TiB. + :param file_attributes: + The file system attributes for files and directories. + If not set, the default value would be "None" and the attributes will be set to "Archive". + Here is an example for when the var type is str: 'Temporary|Archive'. + file_attributes value is not case sensitive. + :type file_attributes: str or ~azure.storage.fileshare.NTFSAttributes + :param file_creation_time: Creation time for the file + Default value: Now. + :type file_creation_time: str or ~datetime.datetime + :param file_last_write_time: Last write time for the file + Default value: Now. + :type file_last_write_time: str or ~datetime.datetime + :param file_permission: If specified the permission (security + descriptor) shall be set for the directory/file. This header can be + used if Permission size is <= 8KB, else x-ms-file-permission-key + header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the + x-ms-file-permission or x-ms-file-permission-key should be specified. + :type file_permission: str + :param permission_key: Key of the permission to be set for the + directory/file. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. + :type permission_key: str + :keyword file_change_time: + Change time for the file. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword metadata: + Name-value pairs associated with the file as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword ~azure.storage.fileshare.ContentSettings content_settings: + ContentSettings object used to set file properties. Used to set content type, encoding, + language, disposition, md5, and cache control. + :keyword bool validate_content: + If true, calculates an MD5 hash for each range of the file. The storage + service checks the hash of the content that has arrived with the hash + that was sent. This is primarily valuable for detecting bitflips on + the wire if using http instead of https as https (the default) will + already validate. Note that this MD5 hash is not stored with the + file. + :keyword int max_concurrency: + Maximum number of parallel connections to use when transferring the file in chunks. + This option does not affect the underlying connection pool, and may + require a separate configuration of the connection pool. + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword progress_hook: + A callback to track the progress of a long running upload. The signature is + function(current: int, total: Optional[int]) where current is the number of bytes transferred + so far, and total is the size of the blob or None if the size is unknown. + :paramtype progress_hook: Callable[[int, Optional[int]], None] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword str encoding: + Defaults to UTF-8. + :returns: File-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_client.py + :start-after: [START upload_file] + :end-before: [END upload_file] + :language: python + :dedent: 12 + :caption: Upload a file. + """ + metadata = kwargs.pop('metadata', None) + content_settings = kwargs.pop('content_settings', None) + max_concurrency = kwargs.pop('max_concurrency', 1) + validate_content = kwargs.pop('validate_content', False) + progress_hook = kwargs.pop('progress_hook', None) + timeout = kwargs.pop('timeout', None) + encoding = kwargs.pop('encoding', 'UTF-8') + + if isinstance(data, str): + data = data.encode(encoding) + if length is None: + length = get_length(data) + if isinstance(data, bytes): + data = data[:length] + + stream: Optional[Any] = None + if isinstance(data, bytes): + stream = BytesIO(data) + elif hasattr(data, 'read'): + stream = data + elif hasattr(data, '__iter__'): + stream = IterStreamer(data, encoding=encoding) + else: + raise TypeError(f"Unsupported data type: {type(data)}") + return _upload_file_helper( + self, + stream, + length, + metadata, + content_settings, + validate_content, + timeout, + max_concurrency, + self._config, + file_attributes=file_attributes, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + file_permission=file_permission, + file_permission_key=permission_key, + progress_hook=progress_hook, + **kwargs) + + @distributed_trace + def start_copy_from_url(self, source_url: str, **kwargs: Any) -> Dict[str, Any]: + """Initiates the copying of data from a source URL into the file + referenced by the client. + + The status of this copy operation can be found using the `get_properties` + method. + + :param str source_url: + Specifies the URL of the source file. + :keyword str file_permission: + If specified the permission (security descriptor) shall be set for the directory/file. + This value can be set to "source" to copy the security descriptor from the source file. + Otherwise if set, this value will be used to override the source value. If not set, permission value + is inherited from the parent directory of the target file. This setting can be + used if Permission size is <= 8KB, otherwise permission_key shall be used. + If SDDL is specified as input, it must have owner, group and dacl. + Note: Only one of the file_permission or permission_key should be specified. + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :keyword str permission_key: + Key of the permission to be set for the directory/file. + This value can be set to "source" to copy the security descriptor from the source file. + Otherwise if set, this value will be used to override the source value. If not set, permission value + is inherited from the parent directory of the target file. + Note: Only one of the file_permission or permission_key should be specified. + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_attributes: + This value can be set to "source" to copy file attributes from the source file to the target file, + or to clear all attributes, it can be set to "None". Otherwise it can be set to a list of attributes + to set on the target file. If this is not set, the default value is "Archive". + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :paramtype file_attributes: str or ~azure.storage.fileshare.NTFSAttributes + :keyword file_creation_time: + This value can be set to "source" to copy the creation time from the source file to the target file, + or a datetime to set as creation time on the target file. This could also be a string in ISO 8601 format. + If this is not set, creation time will be set to the date time value of the creation + (or when it was overwritten) of the target file by copy engine. + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :paramtype file_creation_time: str or ~datetime.datetime + :keyword file_last_write_time: + This value can be set to "source" to copy the last write time from the source file to the target file, or + a datetime to set as the last write time on the target file. This could also be a string in ISO 8601 format. + If this is not set, value will be the last write time to the file by the copy engine. + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :paramtype file_last_write_time: str or ~datetime.datetime + :keyword file_change_time: + Change time for the file. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.9.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword bool ignore_read_only: + Specifies the option to overwrite the target file if it already exists and has read-only attribute set. + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :keyword bool set_archive_attribute: + Specifies the option to set the archive attribute on the target file. + True means the archive attribute will be set on the target file despite attribute + overrides or the source file state. + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :keyword metadata: + Name-value pairs associated with the file as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword str owner: + NFS only. The owner of the file. + :keyword str group: + NFS only. The owning group of the file. + :keyword str file_mode: + NFS only. The file mode of the file. + :keyword file_mode_copy_mode: + NFS only. Applicable only when the copy source is a File. Determines the copy behavior + of the mode bits of the file. Possible values are: + + source - The mode on the destination file is copied from the source file. + override - The mode on the destination file is determined via the file_mode keyword. + :paramtype file_mode_copy_mode: Literal['source', 'override'] + :keyword owner_copy_mode: + NFS only. Applicable only when the copy source is a File. Determines the copy behavior + of the owner and group of the file. Possible values are: + + source - The owner and group on the destination file is copied from the source file. + override - The owner and group on the destination file is determined via the owner and group keywords. + :paramtype owner_copy_mode: Literal['source', 'override'] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: Response after data copying operation has been initiated. + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_client.py + :start-after: [START copy_file_from_url] + :end-before: [END copy_file_from_url] + :language: python + :dedent: 12 + :caption: Copy a file from a URL + """ + metadata = kwargs.pop('metadata', None) + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + owner = kwargs.pop('owner', None) + group = kwargs.pop('group', None) + file_mode = kwargs.pop('file_mode', None) + file_mode_copy_mode = kwargs.pop('file_mode_copy_mode', None) + file_owner_copy_mode = kwargs.pop('owner_copy_mode', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + kwargs.update(get_smb_properties(kwargs)) + try: + return cast(Dict[str, Any], self._client.file.start_copy( + source_url, + metadata=metadata, + lease_access_conditions=access_conditions, + owner=owner, + group=group, + file_mode=file_mode, + file_mode_copy_mode=file_mode_copy_mode, + file_owner_copy_mode=file_owner_copy_mode, + headers=headers, + cls=return_response_headers, + timeout=timeout, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def abort_copy(self, copy_id: Union[str, FileProperties], **kwargs: Any) -> None: + """Abort an ongoing copy operation. + + This will leave a destination file with zero length and full metadata. + This will raise an error if the copy operation has already ended. + + :param copy_id: + The copy operation to abort. This can be either an ID, or an + instance of FileProperties. + :type copy_id: str or ~azure.storage.fileshare.FileProperties + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + + if isinstance(copy_id, FileProperties): + copy_id = copy_id.copy.id + elif isinstance(copy_id, Dict): + copy_id = copy_id['copy_id'] + try: + self._client.file.abort_copy(copy_id=copy_id, + lease_access_conditions=access_conditions, + timeout=timeout, **kwargs) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def download_file( + self, offset: Optional[int] = None, + length: Optional[int] = None, + **kwargs: Any + ) -> StorageStreamDownloader: + """Downloads a file to the StorageStreamDownloader. The readall() method must + be used to read all the content or readinto() must be used to download the file into + a stream. Using chunks() returns an iterator which allows the user to iterate over the content in chunks. + + :param int offset: + Start of byte range to use for downloading a section of the file. + Must be set if length is provided. + :param int length: + Number of bytes to read from the stream. This is optional, but + should be supplied for optimal performance. + :keyword int max_concurrency: + Maximum number of parallel connections to use when transferring the file in chunks. + This option does not affect the underlying connection pool, and may + require a separate configuration of the connection pool. + :keyword bool validate_content: + If true, calculates an MD5 hash for each chunk of the file. The storage + service checks the hash of the content that has arrived with the hash + that was sent. This is primarily valuable for detecting bitflips on + the wire if using http instead of https as https (the default) will + already validate. Note that this MD5 hash is not stored with the + file. Also note that if enabled, the memory-efficient upload algorithm + will not be used, because computing the MD5 hash requires buffering + entire blocks, and doing so defeats the purpose of the memory-efficient algorithm. + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword progress_hook: + A callback to track the progress of a long running download. The signature is + function(current: int, total: int) where current is the number of bytes transferred + so far, and total is the total size of the download. + :paramtype progress_hook: Callable[[int, int], None] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: A streaming object (StorageStreamDownloader) + :rtype: ~azure.storage.fileshare.StorageStreamDownloader + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_client.py + :start-after: [START download_file] + :end-before: [END download_file] + :language: python + :dedent: 12 + :caption: Download a file. + """ + range_end = None + if length is not None: + if offset is None: + raise ValueError("Offset value must not be None if length is set.") + range_end = offset + length - 1 # Service actually uses an end-range inclusive index + + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + + return StorageStreamDownloader( + client=self._client.file, + config=self._config, + start_range=offset, + end_range=range_end, + name=self.file_name, + path='/'.join(self.file_path), + share=self.share_name, + lease_access_conditions=access_conditions, + cls=deserialize_file_stream, + **kwargs) + + @distributed_trace + def delete_file(self, **kwargs: Any) -> None: + """Marks the specified file for deletion. The file is + later deleted during garbage collection. + + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_client.py + :start-after: [START delete_file] + :end-before: [END delete_file] + :language: python + :dedent: 12 + :caption: Delete a file. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + self._client.file.delete(lease_access_conditions=access_conditions, timeout=timeout, **kwargs) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def rename_file(self, new_name: str, **kwargs: Any) -> "ShareFileClient": + """ + Rename the source file. + + :param str new_name: + The new file name. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword bool overwrite: + A boolean value for if the destination file already exists, whether this request will + overwrite the file or not. If true, the rename will succeed and will overwrite the + destination file. If not provided or if false and the destination file does exist, the + request will not overwrite the destination file. If provided and the destination file + doesn't exist, the rename will succeed. + :keyword bool ignore_read_only: + A boolean value that specifies whether the ReadOnly attribute on a preexisting destination + file should be respected. If true, the rename will succeed, otherwise, a previous file at the + destination with the ReadOnly attribute set will cause the rename to fail. + :keyword str file_permission: + If specified the permission (security descriptor) shall be set for the file. This header + can be used if Permission size is <= 8KB, else file_permission_key shall be used. + If SDDL is specified as input, it must have owner, group and dacl. + A value of 'preserve' can be passed to preserve source permissions. + Note: Only one of the file_permission or file_permission_key should be specified. + :keyword str file_permission_key: + Key of the permission to be set for the file. + Note: Only one of the file-permission or file-permission-key should be specified. + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_attributes: + The file system attributes for the file. + :paramtype file_attributes: ~azure.storage.fileshare.NTFSAttributes or str + :keyword file_creation_time: + Creation time for the file. + :paramtype file_creation_time: ~datetime.datetime or str + :keyword file_last_write_time: + Last write time for the file. + :paramtype file_last_write_time: ~datetime.datetime or str + :keyword file_change_time: + Change time for the file. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword str content_type: + The Content Type of the new file. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :keyword Dict[str,str] metadata: + A name-value pair to associate with a file storage object. + :keyword source_lease: + Required if the source file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + :paramtype source_lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword destination_lease: + Required if the destination file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + :paramtype destination_lease: ~azure.storage.fileshare.ShareLeaseClient or str + :returns: The new File Client. + :rtype: ~azure.storage.fileshare.ShareFileClient + """ + if not new_name: + raise ValueError("Please specify a new file name.") + + new_name = new_name.strip('/') + new_path_and_query = new_name.split('?') + new_file_path = new_path_and_query[0] + if len(new_path_and_query) == 2: + new_file_sas = new_path_and_query[1] or self._query_str.strip('?') + else: + new_file_sas = self._query_str.strip('?') + + new_file_client = ShareFileClient( + f'{self.scheme}://{self.primary_hostname}', self.share_name, new_file_path, + credential=new_file_sas or self.credential, api_version=self.api_version, + _hosts=self._hosts, _configuration=self._config, _pipeline=self._pipeline, + _location_mode=self._location_mode, allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, token_intent=self.file_request_intent + ) + + kwargs.update(get_rename_smb_properties(kwargs)) + + file_http_headers = None + content_type = kwargs.pop('content_type', None) + if content_type: + file_http_headers = FileHTTPHeaders( + file_content_type=content_type + ) + + timeout = kwargs.pop('timeout', None) + overwrite = kwargs.pop('overwrite', None) + metadata = kwargs.pop('metadata', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + + source_access_conditions = get_source_access_conditions(kwargs.pop('source_lease', None)) + dest_access_conditions = get_dest_access_conditions(kwargs.pop('destination_lease', None)) + + try: + new_file_client._client.file.rename( # pylint: disable=protected-access + self.url, + timeout=timeout, + replace_if_exists=overwrite, + file_http_headers=file_http_headers, + source_lease_access_conditions=source_access_conditions, + destination_lease_access_conditions=dest_access_conditions, + headers=headers, + **kwargs) + + return new_file_client + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def get_file_properties(self, **kwargs: Any) -> FileProperties: + """Returns all user-defined metadata, standard HTTP properties, and + system properties for the file. + + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: FileProperties + :rtype: ~azure.storage.fileshare.FileProperties + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + file_props = cast(FileProperties, self._client.file.get_properties( + sharesnapshot=self.snapshot, + lease_access_conditions=access_conditions, + timeout=timeout, + cls=deserialize_file_properties, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + file_props.name = self.file_name + file_props.share = self.share_name + file_props.snapshot = self.snapshot + file_props.path = '/'.join(self.file_path) + return file_props + + @distributed_trace + def set_http_headers( + self, content_settings: "ContentSettings", + file_attributes: Optional[Union[str, "NTFSAttributes"]] = None, + file_creation_time: Optional[Union[str, datetime]] = None, + file_last_write_time: Optional[Union[str, datetime]] = None, + file_permission: Optional[str] = None, + permission_key: Optional[str] = None, + **kwargs: Any + ) -> Dict[str, Any]: + """Sets HTTP headers on the file. + + :param ~azure.storage.fileshare.ContentSettings content_settings: + ContentSettings object used to set file properties. Used to set content type, encoding, + language, disposition, md5, and cache control. + :param file_attributes: + The file system attributes for files and directories. + If not set, indicates preservation of existing values. + Here is an example for when the var type is str: 'Temporary|Archive' + :type file_attributes: str or ~azure.storage.fileshare.NTFSAttributes or None + :param file_creation_time: Creation time for the file + Default value: Preserve. + :type file_creation_time: str or ~datetime.datetime or None + :param file_last_write_time: Last write time for the file + Default value: Preserve. + :type file_last_write_time: str or ~datetime.datetime or None + :param file_permission: If specified the permission (security + descriptor) shall be set for the directory/file. This header can be + used if Permission size is <= 8KB, else x-ms-file-permission-key + header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the + x-ms-file-permission or x-ms-file-permission-key should be specified. + :type file_permission: str + :param permission_key: Key of the permission to be set for the + directory/file. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. + :type permission_key: str + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_change_time: + Change time for the file. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword str owner: + NFS only. The owner of the file. + :keyword str group: + NFS only. The owning group of the file. + :keyword str file_mode: + NFS only. The file mode of the file. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + file_content_length = kwargs.pop('size', None) + file_http_headers = FileHTTPHeaders( + file_cache_control=content_settings.cache_control, + file_content_type=content_settings.content_type, + file_content_md5=bytearray(content_settings.content_md5) if content_settings.content_md5 else None, + file_content_encoding=content_settings.content_encoding, + file_content_language=content_settings.content_language, + file_content_disposition=content_settings.content_disposition + ) + file_permission = _get_file_permission(file_permission, permission_key, None) + file_change_time = kwargs.pop('file_change_time', None) + try: + return cast(Dict[str, Any], self._client.file.set_http_headers( + file_content_length=file_content_length, + file_http_headers=file_http_headers, + file_attributes=str(file_attributes) if file_attributes is not None else file_attributes, + file_creation_time=_datetime_to_str(file_creation_time), + file_last_write_time=_datetime_to_str(file_last_write_time), + file_change_time=_datetime_to_str(file_change_time), + file_permission=file_permission, + file_permission_key=permission_key, + lease_access_conditions=access_conditions, + timeout=timeout, + cls=return_response_headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def set_file_metadata(self, metadata: Optional[Dict[str, Any]] = None, **kwargs: Any) -> Dict[str, Any]: + """Sets user-defined metadata for the specified file as one or more + name-value pairs. + + Each call to this operation replaces all existing metadata + attached to the file. To remove all metadata from the file, + call this operation with no metadata dict. + + :param metadata: + Name-value pairs associated with the file as metadata. + :type metadata: dict[str, str] + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + try: + return cast(Dict[str, Any], self._client.file.set_metadata( + timeout=timeout, + cls=return_response_headers, + headers=headers, + metadata=metadata, + lease_access_conditions=access_conditions, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def upload_range( + self, data: bytes, + offset: int, + length: int, + **kwargs: Any + ) -> Dict[str, Any]: + """Upload a range of bytes to a file. + + :param bytes data: + The data to upload. + :param int offset: + Start of byte range to use for uploading a section of the file. + The range can be up to 4 MB in size. + :param int length: + Number of bytes to use for uploading a section of the file. + The range can be up to 4 MB in size. + :keyword bool validate_content: + If true, calculates an MD5 hash of the page content. The storage + service checks the hash of the content that has arrived + with the hash that was sent. This is primarily valuable for detecting + bitflips on the wire if using http instead of https as https (the default) + will already validate. Note that this MD5 hash is not stored with the + file. + :keyword file_last_write_mode: + If the file last write time should be preserved or overwritten. Possible values + are "preserve" or "now". If not specified, file last write time will be changed to + the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_last_write_mode: Literal["preserve", "now"] + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword str encoding: + Defaults to UTF-8. + :returns: File-updated property dict (Etag and last modified). + :rtype: Dict[str, Any] + """ + validate_content = kwargs.pop('validate_content', False) + timeout = kwargs.pop('timeout', None) + encoding = kwargs.pop('encoding', 'UTF-8') + file_last_write_mode = kwargs.pop('file_last_write_mode', None) + if isinstance(data, str): + data = data.encode(encoding) + + end_range = offset + length - 1 # Reformat to an inclusive range index + content_range = f'bytes={offset}-{end_range}' + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + try: + return cast(Dict[str, Any], self._client.file.upload_range( + range=content_range, + content_length=length, + optionalbody=data, + timeout=timeout, + validate_content=validate_content, + file_last_written_mode=file_last_write_mode, + lease_access_conditions=access_conditions, + cls=return_response_headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def upload_range_from_url( + self, source_url: str, + offset: int, + length: int, + source_offset: int, + **kwargs: Any + ) -> Dict[str, Any]: + """ + Writes the bytes from one Azure File endpoint into the specified range of another Azure File endpoint. + + :param int offset: + Start of byte range to use for updating a section of the file. + The range can be up to 4 MB in size. + :param int length: + Number of bytes to use for updating a section of the file. + The range can be up to 4 MB in size. + :param str source_url: + A URL of up to 2 KB in length that specifies an Azure file or blob. + The value should be URL-encoded as it would appear in a request URI. + If the source is in another account, the source must either be public + or must be authenticated via a shared access signature. If the source + is public, no authentication is required. + Examples: + https://myaccount.file.core.windows.net/myshare/mydir/myfile + https://otheraccount.file.core.windows.net/myshare/mydir/myfile?sastoken + :param int source_offset: + This indicates the start of the range of bytes(inclusive) that has to be taken from the copy source. + The service will read the same number of bytes as the destination range (length-offset). + :keyword ~datetime.datetime source_if_modified_since: + A DateTime value. Azure expects the date value passed in to be UTC. + If timezone is included, any non-UTC datetimes will be converted to UTC. + If a date is passed in without timezone info, it is assumed to be UTC. + Specify this conditional header to copy the blob only if the source + blob has been modified since the specified date/time. + :keyword ~datetime.datetime source_if_unmodified_since: + A DateTime value. Azure expects the date value passed in to be UTC. + If timezone is included, any non-UTC datetimes will be converted to UTC. + If a date is passed in without timezone info, it is assumed to be UTC. + Specify this conditional header to copy the blob only if the source blob + has not been modified since the specified date/time. + :keyword str source_etag: + The source ETag value, or the wildcard character (*). Used to check if the resource has changed, + and act according to the condition specified by the `match_condition` parameter. + :keyword ~azure.core.MatchConditions source_match_condition: + The source match condition to use upon the etag. + :keyword file_last_write_mode: + If the file last write time should be preserved or overwritten. Possible values + are "preserve" or "now". If not specified, file last write time will be changed to + the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_last_write_mode: Literal["preserve", "now"] + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword str source_authorization: + Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is + the prefix of the source_authorization string. + :returns: Result after writing to the specified range of the destination Azure File endpoint. + :rtype: dict[str, Any] + """ + options = _upload_range_from_url_options( + source_url=source_url, + offset=offset, + length=length, + source_offset=source_offset, + **kwargs + ) + try: + return cast(Dict[str, Any], self._client.file.upload_range_from_url(**options)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def get_ranges( + self, offset: Optional[int] = None, + length: Optional[int] = None, + **kwargs: Any + ) -> List[Dict[str, int]]: + """Returns the list of valid page ranges for a file or snapshot + of a file. + + :param int offset: + Specifies the start offset of bytes over which to get ranges. + :param int length: + Number of bytes to use over which to get ranges. + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: + A list of valid ranges. + :rtype: List[dict[str, int]] + """ + options = _get_ranges_options( + snapshot=self.snapshot, + offset=offset, + length=length, + **kwargs) + try: + ranges = self._client.file.get_range_list(**options) + except HttpResponseError as error: + process_storage_error(error) + return [{'start': file_range.start, 'end': file_range.end} for file_range in ranges.ranges] + + @distributed_trace + def get_ranges_diff( + self, previous_sharesnapshot: Union[str, Dict[str, Any]], + offset: Optional[int] = None, + length: Optional[int] = None, + *, + include_renames: Optional[bool] = None, + **kwargs: Any + ) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]: + """Returns the list of valid page ranges for a file or snapshot + of a file. + + .. versionadded:: 12.6.0 + + :param int offset: + Specifies the start offset of bytes over which to get ranges. + :param int length: + Number of bytes to use over which to get ranges. + :param str previous_sharesnapshot: + The snapshot diff parameter that contains an opaque DateTime value that + specifies a previous file snapshot to be compared + against a more recent snapshot or the current file. + :keyword Optional[bool] include_renames: + Only valid if previous_sharesnapshot parameter is provided. Specifies whether the changed ranges for + a file that has been renamed or moved between the target snapshot (or live file) and the previous + snapshot should be listed. If set to True, the valid changed ranges for the file will be returned. + If set to False, the operation will result in a 409 (Conflict) response. + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: + A tuple of two lists of file ranges as dictionaries with 'start' and 'end' keys. + The first element are filled file ranges, the 2nd element is cleared file ranges. + :rtype: tuple[list[dict[str, str], list[dict[str, str]] + """ + options = _get_ranges_options( + snapshot=self.snapshot, + offset=offset, + length=length, + previous_sharesnapshot=previous_sharesnapshot, + support_rename=include_renames, + **kwargs) + try: + ranges = self._client.file.get_range_list(**options) + except HttpResponseError as error: + process_storage_error(error) + return get_file_ranges_result(ranges) + + @distributed_trace + def clear_range(self, offset: int, length: int, **kwargs: Any) -> Dict[str, Any]: + """Clears the specified range and releases the space used in storage for + that range. + + :param int offset: + Start of byte range to use for clearing a section of the file. + The range can be up to 4 MB in size. + :param int length: + Number of bytes to use for clearing a section of the file. + The range can be up to 4 MB in size. + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (Etag and last modified). + :rtype: Dict[str, Any] + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + + if offset is None or offset % 512 != 0: + raise ValueError("offset must be an integer that aligns with 512 bytes file size") + if length is None or length % 512 != 0: + raise ValueError("length must be an integer that aligns with 512 bytes file size") + end_range = length + offset - 1 # Reformat to an inclusive range index + content_range = f'bytes={offset}-{end_range}' + try: + return cast(Dict[str, Any], self._client.file.upload_range( + timeout=timeout, + cls=return_response_headers, + content_length=0, + optionalbody=None, + file_range_write="clear", + range=content_range, + lease_access_conditions=access_conditions, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def resize_file(self, size: int, **kwargs: Any) -> Dict[str, Any]: + """Resizes a file to the specified size. + + :param int size: + Size to resize file to (in bytes) + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (Etag and last modified). + :rtype: Dict[str, Any] + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + return cast(Dict[str, Any], self._client.file.set_http_headers( + file_content_length=size, + file_attributes=None, + file_creation_time=None, + file_last_write_time=None, + file_permission="preserve", + lease_access_conditions=access_conditions, + cls=return_response_headers, + timeout=timeout, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def list_handles(self, **kwargs: Any) -> ItemPaged[Handle]: + """Lists handles for file. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: An auto-paging iterable of Handle + :rtype: ~azure.core.paging.ItemPaged[~azure.storage.fileshare.Handle] + """ + timeout = kwargs.pop('timeout', None) + results_per_page = kwargs.pop('results_per_page', None) + command = functools.partial( + self._client.file.list_handles, + sharesnapshot=self.snapshot, + timeout=timeout, + **kwargs) + return ItemPaged( + command, results_per_page=results_per_page, + page_iterator_class=HandlesPaged) + + @distributed_trace + def close_handle(self, handle: Union[str, Handle], **kwargs: Any) -> Dict[str, int]: + """Close an open file handle. + + :param handle: + A specific handle to close. + :type handle: str or ~azure.storage.fileshare.Handle + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: + The number of handles closed (this may be 0 if the specified handle was not found) + and the number of handles failed to close in a dict. + :rtype: dict[str, int] + """ + if isinstance(handle, Handle): + handle_id = handle.id + else: + handle_id = handle + if handle_id == '*': + raise ValueError("Handle ID '*' is not supported. Use 'close_all_handles' instead.") + try: + response = self._client.file.force_close_handles( + handle_id, + marker=None, + sharesnapshot=self.snapshot, + cls=return_response_headers, + **kwargs + ) + return { + 'closed_handles_count': response.get('number_of_handles_closed', 0), + 'failed_handles_count': response.get('number_of_handles_failed', 0) + } + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def close_all_handles(self, **kwargs: Any) -> Dict[str, int]: + """Close any open file handles. + + This operation will block until the service has closed all open handles. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: The number of handles closed (this may be 0 if the specified handle was not found) + and the number of handles failed to close in a dict. + :rtype: dict[str, int] + """ + timeout = kwargs.pop('timeout', None) + start_time = time.time() + + try_close = True + continuation_token = None + total_closed = 0 + total_failed = 0 + while try_close: + try: + response = self._client.file.force_close_handles( + handle_id='*', + timeout=timeout, + marker=continuation_token, + sharesnapshot=self.snapshot, + cls=return_response_headers, + **kwargs + ) + except HttpResponseError as error: + process_storage_error(error) + continuation_token = response.get('marker') + try_close = bool(continuation_token) + total_closed += response.get('number_of_handles_closed', 0) + total_failed += response.get('number_of_handles_failed', 0) + if timeout: + timeout = max(0, timeout - (time.time() - start_time)) + return { + 'closed_handles_count': total_closed, + 'failed_handles_count': total_failed + } + + @distributed_trace + def create_hardlink( + self, target: str, + *, + lease: Optional[Union[ShareLeaseClient, str]] = None, + timeout: Optional[int] = None, + **kwargs: Any + ) -> Dict[str, Any]: + """NFS only. Creates a hard link to the file specified by path. + + :param str target: + Specifies the path of the target file to which the link will be created, up to 2 KiB in length. + It should be the full path of the target starting from the root. The target file must be in the + same share and the same storage account. + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (ETag and last modified). + :rtype: dict[str, Any] + """ + try: + return cast(Dict[str, Any], self._client.file.create_hard_link( + target_file=target, + lease_access_conditions=lease, + timeout=timeout, + cls=return_response_headers, + **kwargs + )) + except HttpResponseError as error: + process_storage_error(error) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_file_client_helpers.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_file_client_helpers.py new file mode 100644 index 00000000..ea225f3c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_file_client_helpers.py @@ -0,0 +1,145 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from typing import ( + Any, Dict, List, Optional, Tuple, Union, + TYPE_CHECKING +) +from urllib.parse import quote, unquote, urlparse + +from ._serialize import get_access_conditions, get_source_conditions +from ._shared.base_client import parse_query +from ._shared.response_handlers import return_response_headers + +if TYPE_CHECKING: + from urllib.parse import ParseResult + + +def _parse_url(account_url: str, share_name: str, file_path: str) -> "ParseResult": + try: + if not account_url.lower().startswith('http'): + account_url = "https://" + account_url + except AttributeError as exc: + raise ValueError("Account URL must be a string.") from exc + parsed_url = urlparse(account_url.rstrip('/')) + if not (share_name and file_path): + raise ValueError("Please specify a share name and file name.") + if not parsed_url.netloc: + raise ValueError(f"Invalid URL: {account_url}") + return parsed_url + + +def _from_file_url( + file_url: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None +) -> Tuple[str, str, str, Optional[Union[str, Dict[str, Any]]]]: + try: + if not file_url.lower().startswith('http'): + file_url = "https://" + file_url + except AttributeError as exc: + raise ValueError("File URL must be a string.") from exc + parsed_url = urlparse(file_url.rstrip('/')) + + if not (parsed_url.netloc and parsed_url.path): + raise ValueError(f"Invalid URL: {file_url}") + account_url = parsed_url.netloc.rstrip('/') + "?" + parsed_url.query + + path_share, _, path_file = parsed_url.path.lstrip('/').partition('/') + path_snapshot, _ = parse_query(parsed_url.query) + snapshot = snapshot or path_snapshot + share_name = unquote(path_share) + file_path = '/'.join([unquote(p) for p in path_file.split('/')]) + + return account_url, share_name, file_path, snapshot + + +def _format_url( + scheme: str, + hostname: str, + share_name: Union[str, bytes], + file_path: List[str], + query_str: str +) -> str: + if isinstance(share_name, str): + share_name = share_name.encode('UTF-8') + return (f"{scheme}://{hostname}/{quote(share_name)}" + f"/{'/'.join([quote(p, safe='~') for p in file_path])}{query_str}") + + +def _upload_range_from_url_options( + source_url: str, + offset: int, + length: int, + source_offset: int, + **kwargs: Any +) -> Dict[str, Any]: + if offset is None: + raise ValueError("offset must be provided.") + if length is None: + raise ValueError("length must be provided.") + if source_offset is None: + raise ValueError("source_offset must be provided.") + + # Format range + end_range = offset + length - 1 + destination_range = f'bytes={offset}-{end_range}' + source_range = f'bytes={source_offset}-{source_offset + length - 1}' + source_authorization = kwargs.pop('source_authorization', None) + source_mod_conditions = get_source_conditions(kwargs) + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + file_last_write_mode = kwargs.pop('file_last_write_mode', None) + + options = { + 'copy_source_authorization': source_authorization, + 'copy_source': source_url, + 'content_length': 0, + 'source_range': source_range, + 'range': destination_range, + 'file_last_written_mode': file_last_write_mode, + 'source_modified_access_conditions': source_mod_conditions, + 'lease_access_conditions': access_conditions, + 'timeout': kwargs.pop('timeout', None), + 'cls': return_response_headers + } + + options.update(kwargs) + return options + + +def _get_ranges_options( + snapshot: Optional[str], + offset: Optional[int] = None, + length: Optional[int] = None, + previous_sharesnapshot: Optional[Union[str, Dict[str, Any]]] = None, + **kwargs: Any +) -> Dict[str, Any]: + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + + content_range = None + if offset: + if length: + end_range = offset + length - 1 # Reformat to an inclusive range index + content_range = f'bytes={offset}-{end_range}' + else: + content_range = f'bytes={offset}-' + + options = { + 'sharesnapshot': snapshot, + 'lease_access_conditions': access_conditions, + 'timeout': kwargs.pop('timeout', None), + 'range': content_range + } + + if previous_sharesnapshot: + if hasattr(previous_sharesnapshot, 'snapshot'): + options['prevsharesnapshot'] = previous_sharesnapshot.snapshot + elif isinstance(previous_sharesnapshot, Dict): + options['prevsharesnapshot'] = previous_sharesnapshot['snapshot'] + else: + options['prevsharesnapshot'] = previous_sharesnapshot + + options.update(kwargs) + return options diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/__init__.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/__init__.py new file mode 100644 index 00000000..b4f1dd31 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/__init__.py @@ -0,0 +1,29 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._azure_file_storage import AzureFileStorage # type: ignore + +try: + from ._patch import __all__ as _patch_all + from ._patch import * +except ImportError: + _patch_all = [] +from ._patch import patch_sdk as _patch_sdk + +__all__ = [ + "AzureFileStorage", +] +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore + +_patch_sdk() diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/_azure_file_storage.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/_azure_file_storage.py new file mode 100644 index 00000000..8a332771 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/_azure_file_storage.py @@ -0,0 +1,130 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from copy import deepcopy +from typing import Any, Optional, Union +from typing_extensions import Self + +from azure.core import PipelineClient +from azure.core.pipeline import policies +from azure.core.rest import HttpRequest, HttpResponse + +from . import models as _models +from ._configuration import AzureFileStorageConfiguration +from ._serialization import Deserializer, Serializer +from .operations import DirectoryOperations, FileOperations, ServiceOperations, ShareOperations + + +class AzureFileStorage: # pylint: disable=client-accepts-api-version-keyword + """AzureFileStorage. + + :ivar service: ServiceOperations operations + :vartype service: azure.storage.fileshare.operations.ServiceOperations + :ivar share: ShareOperations operations + :vartype share: azure.storage.fileshare.operations.ShareOperations + :ivar directory: DirectoryOperations operations + :vartype directory: azure.storage.fileshare.operations.DirectoryOperations + :ivar file: FileOperations operations + :vartype file: azure.storage.fileshare.operations.FileOperations + :param url: The URL of the service account, share, directory or file that is the target of the + desired operation. Required. + :type url: str + :param base_url: Service URL. Required. Default value is "". + :type base_url: str + :param file_request_intent: Valid value is backup. "backup" Default value is None. + :type file_request_intent: str or ~azure.storage.fileshare.models.ShareTokenIntent + :param allow_trailing_dot: If true, the trailing dot will not be trimmed from the target URI. + Default value is None. + :type allow_trailing_dot: bool + :param allow_source_trailing_dot: If true, the trailing dot will not be trimmed from the source + URI. Default value is None. + :type allow_source_trailing_dot: bool + :keyword version: Specifies the version of the operation to use for this request. Default value + is "2025-05-05". Note that overriding this default value may result in unsupported behavior. + :paramtype version: str + :keyword file_range_write_from_url: Only update is supported: - Update: Writes the bytes + downloaded from the source url into the specified range. Default value is "update". Note that + overriding this default value may result in unsupported behavior. + :paramtype file_range_write_from_url: str + """ + + def __init__( # pylint: disable=missing-client-constructor-parameter-credential + self, + url: str, + base_url: str = "", + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + allow_trailing_dot: Optional[bool] = None, + allow_source_trailing_dot: Optional[bool] = None, + **kwargs: Any + ) -> None: + self._config = AzureFileStorageConfiguration( + url=url, + file_request_intent=file_request_intent, + allow_trailing_dot=allow_trailing_dot, + allow_source_trailing_dot=allow_source_trailing_dot, + **kwargs + ) + _policies = kwargs.pop("policies", None) + if _policies is None: + _policies = [ + policies.RequestIdPolicy(**kwargs), + self._config.headers_policy, + self._config.user_agent_policy, + self._config.proxy_policy, + policies.ContentDecodePolicy(**kwargs), + self._config.redirect_policy, + self._config.retry_policy, + self._config.authentication_policy, + self._config.custom_hook_policy, + self._config.logging_policy, + policies.DistributedTracingPolicy(**kwargs), + policies.SensitiveHeaderCleanupPolicy(**kwargs) if self._config.redirect_policy else None, + self._config.http_logging_policy, + ] + self._client: PipelineClient = PipelineClient(base_url=base_url, policies=_policies, **kwargs) + + client_models = {k: v for k, v in _models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._deserialize = Deserializer(client_models) + self._serialize.client_side_validation = False + self.service = ServiceOperations(self._client, self._config, self._serialize, self._deserialize) + self.share = ShareOperations(self._client, self._config, self._serialize, self._deserialize) + self.directory = DirectoryOperations(self._client, self._config, self._serialize, self._deserialize) + self.file = FileOperations(self._client, self._config, self._serialize, self._deserialize) + + def _send_request(self, request: HttpRequest, *, stream: bool = False, **kwargs: Any) -> HttpResponse: + """Runs the network request through the client's chained policies. + + >>> from azure.core.rest import HttpRequest + >>> request = HttpRequest("GET", "https://www.example.org/") + <HttpRequest [GET], url: 'https://www.example.org/'> + >>> response = client._send_request(request) + <HttpResponse: 200 OK> + + For more information on this code flow, see https://aka.ms/azsdk/dpcodegen/python/send_request + + :param request: The network request you want to make. Required. + :type request: ~azure.core.rest.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to False. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.rest.HttpResponse + """ + + request_copy = deepcopy(request) + request_copy.url = self._client.format_url(request_copy.url) + return self._client.send_request(request_copy, stream=stream, **kwargs) # type: ignore + + def close(self) -> None: + self._client.close() + + def __enter__(self) -> Self: + self._client.__enter__() + return self + + def __exit__(self, *exc_details: Any) -> None: + self._client.__exit__(*exc_details) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/_configuration.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/_configuration.py new file mode 100644 index 00000000..6b42bcdf --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/_configuration.py @@ -0,0 +1,77 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, Literal, Optional, Union + +from azure.core.pipeline import policies + +from . import models as _models + +VERSION = "unknown" + + +class AzureFileStorageConfiguration: # pylint: disable=too-many-instance-attributes + """Configuration for AzureFileStorage. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param url: The URL of the service account, share, directory or file that is the target of the + desired operation. Required. + :type url: str + :param file_request_intent: Valid value is backup. "backup" Default value is None. + :type file_request_intent: str or ~azure.storage.fileshare.models.ShareTokenIntent + :param allow_trailing_dot: If true, the trailing dot will not be trimmed from the target URI. + Default value is None. + :type allow_trailing_dot: bool + :param allow_source_trailing_dot: If true, the trailing dot will not be trimmed from the source + URI. Default value is None. + :type allow_source_trailing_dot: bool + :keyword version: Specifies the version of the operation to use for this request. Default value + is "2025-05-05". Note that overriding this default value may result in unsupported behavior. + :paramtype version: str + :keyword file_range_write_from_url: Only update is supported: - Update: Writes the bytes + downloaded from the source url into the specified range. Default value is "update". Note that + overriding this default value may result in unsupported behavior. + :paramtype file_range_write_from_url: str + """ + + def __init__( + self, + url: str, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + allow_trailing_dot: Optional[bool] = None, + allow_source_trailing_dot: Optional[bool] = None, + **kwargs: Any + ) -> None: + version: Literal["2025-05-05"] = kwargs.pop("version", "2025-05-05") + file_range_write_from_url: Literal["update"] = kwargs.pop("file_range_write_from_url", "update") + + if url is None: + raise ValueError("Parameter 'url' must not be None.") + + self.url = url + self.file_request_intent = file_request_intent + self.allow_trailing_dot = allow_trailing_dot + self.allow_source_trailing_dot = allow_source_trailing_dot + self.version = version + self.file_range_write_from_url = file_range_write_from_url + kwargs.setdefault("sdk_moniker", "azurefilestorage/{}".format(VERSION)) + self.polling_interval = kwargs.get("polling_interval", 30) + self._configure(**kwargs) + + def _configure(self, **kwargs: Any) -> None: + self.user_agent_policy = kwargs.get("user_agent_policy") or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get("headers_policy") or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get("proxy_policy") or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get("logging_policy") or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get("http_logging_policy") or policies.HttpLoggingPolicy(**kwargs) + self.custom_hook_policy = kwargs.get("custom_hook_policy") or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get("redirect_policy") or policies.RedirectPolicy(**kwargs) + self.retry_policy = kwargs.get("retry_policy") or policies.RetryPolicy(**kwargs) + self.authentication_policy = kwargs.get("authentication_policy") diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/_patch.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/_patch.py new file mode 100644 index 00000000..f7dd3251 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/_patch.py @@ -0,0 +1,20 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Customize generated code here. + +Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize +""" +from typing import List + +__all__: List[str] = [] # Add all objects you want publicly available to users at this package level + + +def patch_sdk(): + """Do not remove from this file. + + `patch_sdk` is a last resort escape hatch that allows you to do customizations + you can't accomplish using the techniques described in + https://aka.ms/azsdk/python/dpcodegen/python/customize + """ diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/_serialization.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/_serialization.py new file mode 100644 index 00000000..a066e16a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/_serialization.py @@ -0,0 +1,2050 @@ +# pylint: disable=too-many-lines +# -------------------------------------------------------------------------- +# +# Copyright (c) Microsoft Corporation. All rights reserved. +# +# The MIT License (MIT) +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the ""Software""), to +# deal in the Software without restriction, including without limitation the +# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +# +# -------------------------------------------------------------------------- + +# pyright: reportUnnecessaryTypeIgnoreComment=false + +from base64 import b64decode, b64encode +import calendar +import datetime +import decimal +import email +from enum import Enum +import json +import logging +import re +import sys +import codecs +from typing import ( + Dict, + Any, + cast, + Optional, + Union, + AnyStr, + IO, + Mapping, + Callable, + MutableMapping, + List, +) + +try: + from urllib import quote # type: ignore +except ImportError: + from urllib.parse import quote +import xml.etree.ElementTree as ET + +import isodate # type: ignore +from typing_extensions import Self + +from azure.core.exceptions import DeserializationError, SerializationError +from azure.core.serialization import NULL as CoreNull + +_BOM = codecs.BOM_UTF8.decode(encoding="utf-8") + +JSON = MutableMapping[str, Any] + + +class RawDeserializer: + + # Accept "text" because we're open minded people... + JSON_REGEXP = re.compile(r"^(application|text)/([a-z+.]+\+)?json$") + + # Name used in context + CONTEXT_NAME = "deserialized_data" + + @classmethod + def deserialize_from_text(cls, data: Optional[Union[AnyStr, IO]], content_type: Optional[str] = None) -> Any: + """Decode data according to content-type. + + Accept a stream of data as well, but will be load at once in memory for now. + + If no content-type, will return the string version (not bytes, not stream) + + :param data: Input, could be bytes or stream (will be decoded with UTF8) or text + :type data: str or bytes or IO + :param str content_type: The content type. + :return: The deserialized data. + :rtype: object + """ + if hasattr(data, "read"): + # Assume a stream + data = cast(IO, data).read() + + if isinstance(data, bytes): + data_as_str = data.decode(encoding="utf-8-sig") + else: + # Explain to mypy the correct type. + data_as_str = cast(str, data) + + # Remove Byte Order Mark if present in string + data_as_str = data_as_str.lstrip(_BOM) + + if content_type is None: + return data + + if cls.JSON_REGEXP.match(content_type): + try: + return json.loads(data_as_str) + except ValueError as err: + raise DeserializationError("JSON is invalid: {}".format(err), err) from err + elif "xml" in (content_type or []): + try: + + try: + if isinstance(data, unicode): # type: ignore + # If I'm Python 2.7 and unicode XML will scream if I try a "fromstring" on unicode string + data_as_str = data_as_str.encode(encoding="utf-8") # type: ignore + except NameError: + pass + + return ET.fromstring(data_as_str) # nosec + except ET.ParseError as err: + # It might be because the server has an issue, and returned JSON with + # content-type XML.... + # So let's try a JSON load, and if it's still broken + # let's flow the initial exception + def _json_attemp(data): + try: + return True, json.loads(data) + except ValueError: + return False, None # Don't care about this one + + success, json_result = _json_attemp(data) + if success: + return json_result + # If i'm here, it's not JSON, it's not XML, let's scream + # and raise the last context in this block (the XML exception) + # The function hack is because Py2.7 messes up with exception + # context otherwise. + _LOGGER.critical("Wasn't XML not JSON, failing") + raise DeserializationError("XML is invalid") from err + elif content_type.startswith("text/"): + return data_as_str + raise DeserializationError("Cannot deserialize content-type: {}".format(content_type)) + + @classmethod + def deserialize_from_http_generics(cls, body_bytes: Optional[Union[AnyStr, IO]], headers: Mapping) -> Any: + """Deserialize from HTTP response. + + Use bytes and headers to NOT use any requests/aiohttp or whatever + specific implementation. + Headers will tested for "content-type" + + :param bytes body_bytes: The body of the response. + :param dict headers: The headers of the response. + :returns: The deserialized data. + :rtype: object + """ + # Try to use content-type from headers if available + content_type = None + if "content-type" in headers: + content_type = headers["content-type"].split(";")[0].strip().lower() + # Ouch, this server did not declare what it sent... + # Let's guess it's JSON... + # Also, since Autorest was considering that an empty body was a valid JSON, + # need that test as well.... + else: + content_type = "application/json" + + if body_bytes: + return cls.deserialize_from_text(body_bytes, content_type) + return None + + +_LOGGER = logging.getLogger(__name__) + +try: + _long_type = long # type: ignore +except NameError: + _long_type = int + +TZ_UTC = datetime.timezone.utc + +_FLATTEN = re.compile(r"(?<!\\)\.") + + +def attribute_transformer(key, attr_desc, value): # pylint: disable=unused-argument + """A key transformer that returns the Python attribute. + + :param str key: The attribute name + :param dict attr_desc: The attribute metadata + :param object value: The value + :returns: A key using attribute name + :rtype: str + """ + return (key, value) + + +def full_restapi_key_transformer(key, attr_desc, value): # pylint: disable=unused-argument + """A key transformer that returns the full RestAPI key path. + + :param str key: The attribute name + :param dict attr_desc: The attribute metadata + :param object value: The value + :returns: A list of keys using RestAPI syntax. + :rtype: list + """ + keys = _FLATTEN.split(attr_desc["key"]) + return ([_decode_attribute_map_key(k) for k in keys], value) + + +def last_restapi_key_transformer(key, attr_desc, value): + """A key transformer that returns the last RestAPI key. + + :param str key: The attribute name + :param dict attr_desc: The attribute metadata + :param object value: The value + :returns: The last RestAPI key. + :rtype: str + """ + key, value = full_restapi_key_transformer(key, attr_desc, value) + return (key[-1], value) + + +def _create_xml_node(tag, prefix=None, ns=None): + """Create a XML node. + + :param str tag: The tag name + :param str prefix: The prefix + :param str ns: The namespace + :return: The XML node + :rtype: xml.etree.ElementTree.Element + """ + if prefix and ns: + ET.register_namespace(prefix, ns) + if ns: + return ET.Element("{" + ns + "}" + tag) + return ET.Element(tag) + + +class Model: + """Mixin for all client request body/response body models to support + serialization and deserialization. + """ + + _subtype_map: Dict[str, Dict[str, Any]] = {} + _attribute_map: Dict[str, Dict[str, Any]] = {} + _validation: Dict[str, Dict[str, Any]] = {} + + def __init__(self, **kwargs: Any) -> None: + self.additional_properties: Optional[Dict[str, Any]] = {} + for k in kwargs: # pylint: disable=consider-using-dict-items + if k not in self._attribute_map: + _LOGGER.warning("%s is not a known attribute of class %s and will be ignored", k, self.__class__) + elif k in self._validation and self._validation[k].get("readonly", False): + _LOGGER.warning("Readonly attribute %s will be ignored in class %s", k, self.__class__) + else: + setattr(self, k, kwargs[k]) + + def __eq__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are equal + :rtype: bool + """ + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + def __ne__(self, other: Any) -> bool: + """Compare objects by comparing all attributes. + + :param object other: The object to compare + :returns: True if objects are not equal + :rtype: bool + """ + return not self.__eq__(other) + + def __str__(self) -> str: + return str(self.__dict__) + + @classmethod + def enable_additional_properties_sending(cls) -> None: + cls._attribute_map["additional_properties"] = {"key": "", "type": "{object}"} + + @classmethod + def is_xml_model(cls) -> bool: + try: + cls._xml_map # type: ignore + except AttributeError: + return False + return True + + @classmethod + def _create_xml_node(cls): + """Create XML node. + + :returns: The XML node + :rtype: xml.etree.ElementTree.Element + """ + try: + xml_map = cls._xml_map # type: ignore + except AttributeError: + xml_map = {} + + return _create_xml_node(xml_map.get("name", cls.__name__), xml_map.get("prefix", None), xml_map.get("ns", None)) + + def serialize(self, keep_readonly: bool = False, **kwargs: Any) -> JSON: + """Return the JSON that would be sent to server from this model. + + This is an alias to `as_dict(full_restapi_key_transformer, keep_readonly=False)`. + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, keep_readonly=keep_readonly, **kwargs + ) + + def as_dict( + self, + keep_readonly: bool = True, + key_transformer: Callable[[str, Dict[str, Any], Any], Any] = attribute_transformer, + **kwargs: Any + ) -> JSON: + """Return a dict that can be serialized using json.dump. + + Advanced usage might optionally use a callback as parameter: + + .. code::python + + def my_key_transformer(key, attr_desc, value): + return key + + Key is the attribute name used in Python. Attr_desc + is a dict of metadata. Currently contains 'type' with the + msrest type and 'key' with the RestAPI encoded key. + Value is the current value in this object. + + The string returned will be used to serialize the key. + If the return type is a list, this is considered hierarchical + result dict. + + See the three examples in this file: + + - attribute_transformer + - full_restapi_key_transformer + - last_restapi_key_transformer + + If you want XML serialization, you can pass the kwargs is_xml=True. + + :param bool keep_readonly: If you want to serialize the readonly attributes + :param function key_transformer: A key transformer function. + :returns: A dict JSON compatible object + :rtype: dict + """ + serializer = Serializer(self._infer_class_models()) + return serializer._serialize( # type: ignore # pylint: disable=protected-access + self, key_transformer=key_transformer, keep_readonly=keep_readonly, **kwargs + ) + + @classmethod + def _infer_class_models(cls): + try: + str_models = cls.__module__.rsplit(".", 1)[0] + models = sys.modules[str_models] + client_models = {k: v for k, v in models.__dict__.items() if isinstance(v, type)} + if cls.__name__ not in client_models: + raise ValueError("Not Autorest generated code") + except Exception: # pylint: disable=broad-exception-caught + # Assume it's not Autorest generated (tests?). Add ourselves as dependencies. + client_models = {cls.__name__: cls} + return client_models + + @classmethod + def deserialize(cls, data: Any, content_type: Optional[str] = None) -> Self: + """Parse a str using the RestAPI syntax and return a model. + + :param str data: A str using RestAPI structure. JSON by default. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises DeserializationError: if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def from_dict( + cls, + data: Any, + key_extractors: Optional[Callable[[str, Dict[str, Any], Any], Any]] = None, + content_type: Optional[str] = None, + ) -> Self: + """Parse a dict using given key extractor return a model. + + By default consider key + extractors (rest_key_case_insensitive_extractor, attribute_key_case_insensitive_extractor + and last_rest_key_case_insensitive_extractor) + + :param dict data: A dict using RestAPI structure + :param function key_extractors: A key extractor function. + :param str content_type: JSON by default, set application/xml if XML. + :returns: An instance of this model + :raises: DeserializationError if something went wrong + :rtype: Self + """ + deserializer = Deserializer(cls._infer_class_models()) + deserializer.key_extractors = ( # type: ignore + [ # type: ignore + attribute_key_case_insensitive_extractor, + rest_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + if key_extractors is None + else key_extractors + ) + return deserializer(cls.__name__, data, content_type=content_type) # type: ignore + + @classmethod + def _flatten_subtype(cls, key, objects): + if "_subtype_map" not in cls.__dict__: + return {} + result = dict(cls._subtype_map[key]) + for valuetype in cls._subtype_map[key].values(): + result.update(objects[valuetype]._flatten_subtype(key, objects)) # pylint: disable=protected-access + return result + + @classmethod + def _classify(cls, response, objects): + """Check the class _subtype_map for any child classes. + We want to ignore any inherited _subtype_maps. + + :param dict response: The initial data + :param dict objects: The class objects + :returns: The class to be used + :rtype: class + """ + for subtype_key in cls.__dict__.get("_subtype_map", {}).keys(): + subtype_value = None + + if not isinstance(response, ET.Element): + rest_api_response_key = cls._get_rest_key_parts(subtype_key)[-1] + subtype_value = response.get(rest_api_response_key, None) or response.get(subtype_key, None) + else: + subtype_value = xml_key_extractor(subtype_key, cls._attribute_map[subtype_key], response) + if subtype_value: + # Try to match base class. Can be class name only + # (bug to fix in Autorest to support x-ms-discriminator-name) + if cls.__name__ == subtype_value: + return cls + flatten_mapping_type = cls._flatten_subtype(subtype_key, objects) + try: + return objects[flatten_mapping_type[subtype_value]] # type: ignore + except KeyError: + _LOGGER.warning( + "Subtype value %s has no mapping, use base class %s.", + subtype_value, + cls.__name__, + ) + break + else: + _LOGGER.warning("Discriminator %s is absent or null, use base class %s.", subtype_key, cls.__name__) + break + return cls + + @classmethod + def _get_rest_key_parts(cls, attr_key): + """Get the RestAPI key of this attr, split it and decode part + :param str attr_key: Attribute key must be in attribute_map. + :returns: A list of RestAPI part + :rtype: list + """ + rest_split_key = _FLATTEN.split(cls._attribute_map[attr_key]["key"]) + return [_decode_attribute_map_key(key_part) for key_part in rest_split_key] + + +def _decode_attribute_map_key(key): + """This decode a key in an _attribute_map to the actual key we want to look at + inside the received data. + + :param str key: A key string from the generated code + :returns: The decoded key + :rtype: str + """ + return key.replace("\\.", ".") + + +class Serializer: # pylint: disable=too-many-public-methods + """Request object model serializer.""" + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + _xml_basic_types_serializers = {"bool": lambda x: str(x).lower()} + days = {0: "Mon", 1: "Tue", 2: "Wed", 3: "Thu", 4: "Fri", 5: "Sat", 6: "Sun"} + months = { + 1: "Jan", + 2: "Feb", + 3: "Mar", + 4: "Apr", + 5: "May", + 6: "Jun", + 7: "Jul", + 8: "Aug", + 9: "Sep", + 10: "Oct", + 11: "Nov", + 12: "Dec", + } + validation = { + "min_length": lambda x, y: len(x) < y, + "max_length": lambda x, y: len(x) > y, + "minimum": lambda x, y: x < y, + "maximum": lambda x, y: x > y, + "minimum_ex": lambda x, y: x <= y, + "maximum_ex": lambda x, y: x >= y, + "min_items": lambda x, y: len(x) < y, + "max_items": lambda x, y: len(x) > y, + "pattern": lambda x, y: not re.match(y, x, re.UNICODE), + "unique": lambda x, y: len(x) != len(set(x)), + "multiple": lambda x, y: x % y != 0, + } + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.serialize_type = { + "iso-8601": Serializer.serialize_iso, + "rfc-1123": Serializer.serialize_rfc, + "unix-time": Serializer.serialize_unix, + "duration": Serializer.serialize_duration, + "date": Serializer.serialize_date, + "time": Serializer.serialize_time, + "decimal": Serializer.serialize_decimal, + "long": Serializer.serialize_long, + "bytearray": Serializer.serialize_bytearray, + "base64": Serializer.serialize_base64, + "object": self.serialize_object, + "[]": self.serialize_iter, + "{}": self.serialize_dict, + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_transformer = full_restapi_key_transformer + self.client_side_validation = True + + def _serialize( # pylint: disable=too-many-nested-blocks, too-many-branches, too-many-statements, too-many-locals + self, target_obj, data_type=None, **kwargs + ): + """Serialize data into a string according to type. + + :param object target_obj: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, dict + :raises SerializationError: if serialization fails. + :returns: The serialized data. + """ + key_transformer = kwargs.get("key_transformer", self.key_transformer) + keep_readonly = kwargs.get("keep_readonly", False) + if target_obj is None: + return None + + attr_name = None + class_name = target_obj.__class__.__name__ + + if data_type: + return self.serialize_data(target_obj, data_type, **kwargs) + + if not hasattr(target_obj, "_attribute_map"): + data_type = type(target_obj).__name__ + if data_type in self.basic_types.values(): + return self.serialize_data(target_obj, data_type, **kwargs) + + # Force "is_xml" kwargs if we detect a XML model + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + is_xml_model_serialization = kwargs.setdefault("is_xml", target_obj.is_xml_model()) + + serialized = {} + if is_xml_model_serialization: + serialized = target_obj._create_xml_node() # pylint: disable=protected-access + try: + attributes = target_obj._attribute_map # pylint: disable=protected-access + for attr, attr_desc in attributes.items(): + attr_name = attr + if not keep_readonly and target_obj._validation.get( # pylint: disable=protected-access + attr_name, {} + ).get("readonly", False): + continue + + if attr_name == "additional_properties" and attr_desc["key"] == "": + if target_obj.additional_properties is not None: + serialized.update(target_obj.additional_properties) + continue + try: + + orig_attr = getattr(target_obj, attr) + if is_xml_model_serialization: + pass # Don't provide "transformer" for XML for now. Keep "orig_attr" + else: # JSON + keys, orig_attr = key_transformer(attr, attr_desc.copy(), orig_attr) + keys = keys if isinstance(keys, list) else [keys] + + kwargs["serialization_ctxt"] = attr_desc + new_attr = self.serialize_data(orig_attr, attr_desc["type"], **kwargs) + + if is_xml_model_serialization: + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + xml_prefix = xml_desc.get("prefix", None) + xml_ns = xml_desc.get("ns", None) + if xml_desc.get("attr", False): + if xml_ns: + ET.register_namespace(xml_prefix, xml_ns) + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + serialized.set(xml_name, new_attr) # type: ignore + continue + if xml_desc.get("text", False): + serialized.text = new_attr # type: ignore + continue + if isinstance(new_attr, list): + serialized.extend(new_attr) # type: ignore + elif isinstance(new_attr, ET.Element): + # If the down XML has no XML/Name, + # we MUST replace the tag with the local tag. But keeping the namespaces. + if "name" not in getattr(orig_attr, "_xml_map", {}): + splitted_tag = new_attr.tag.split("}") + if len(splitted_tag) == 2: # Namespace + new_attr.tag = "}".join([splitted_tag[0], xml_name]) + else: + new_attr.tag = xml_name + serialized.append(new_attr) # type: ignore + else: # That's a basic type + # Integrate namespace if necessary + local_node = _create_xml_node(xml_name, xml_prefix, xml_ns) + local_node.text = str(new_attr) + serialized.append(local_node) # type: ignore + else: # JSON + for k in reversed(keys): # type: ignore + new_attr = {k: new_attr} + + _new_attr = new_attr + _serialized = serialized + for k in keys: # type: ignore + if k not in _serialized: + _serialized.update(_new_attr) # type: ignore + _new_attr = _new_attr[k] # type: ignore + _serialized = _serialized[k] + except ValueError as err: + if isinstance(err, SerializationError): + raise + + except (AttributeError, KeyError, TypeError) as err: + msg = "Attribute {} in object {} cannot be serialized.\n{}".format(attr_name, class_name, str(target_obj)) + raise SerializationError(msg) from err + return serialized + + def body(self, data, data_type, **kwargs): + """Serialize data intended for a request body. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: dict + :raises SerializationError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized request body + """ + + # Just in case this is a dict + internal_data_type_str = data_type.strip("[]{}") + internal_data_type = self.dependencies.get(internal_data_type_str, None) + try: + is_xml_model_serialization = kwargs["is_xml"] + except KeyError: + if internal_data_type and issubclass(internal_data_type, Model): + is_xml_model_serialization = kwargs.setdefault("is_xml", internal_data_type.is_xml_model()) + else: + is_xml_model_serialization = False + if internal_data_type and not isinstance(internal_data_type, Enum): + try: + deserializer = Deserializer(self.dependencies) + # Since it's on serialization, it's almost sure that format is not JSON REST + # We're not able to deal with additional properties for now. + deserializer.additional_properties_detection = False + if is_xml_model_serialization: + deserializer.key_extractors = [ # type: ignore + attribute_key_case_insensitive_extractor, + ] + else: + deserializer.key_extractors = [ + rest_key_case_insensitive_extractor, + attribute_key_case_insensitive_extractor, + last_rest_key_case_insensitive_extractor, + ] + data = deserializer._deserialize(data_type, data) # pylint: disable=protected-access + except DeserializationError as err: + raise SerializationError("Unable to build a model: " + str(err)) from err + + return self._serialize(data, data_type, **kwargs) + + def url(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL path. + + :param str name: The name of the URL path parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :returns: The serialized URL path + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + """ + try: + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + + if kwargs.get("skip_quote") is True: + output = str(output) + output = output.replace("{", quote("{")).replace("}", quote("}")) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return output + + def query(self, name, data, data_type, **kwargs): + """Serialize data intended for a URL query. + + :param str name: The name of the query parameter. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str, list + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized query parameter + """ + try: + # Treat the list aside, since we don't want to encode the div separator + if data_type.startswith("["): + internal_data_type = data_type[1:-1] + do_quote = not kwargs.get("skip_quote", False) + return self.serialize_iter(data, internal_data_type, do_quote=do_quote, **kwargs) + + # Not a list, regular serialization + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + if kwargs.get("skip_quote") is True: + output = str(output) + else: + output = quote(str(output), safe="") + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def header(self, name, data, data_type, **kwargs): + """Serialize data intended for a request header. + + :param str name: The name of the header. + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :rtype: str + :raises TypeError: if serialization fails. + :raises ValueError: if data is None + :returns: The serialized header + """ + try: + if data_type in ["[str]"]: + data = ["" if d is None else d for d in data] + + output = self.serialize_data(data, data_type, **kwargs) + if data_type == "bool": + output = json.dumps(output) + except SerializationError as exc: + raise TypeError("{} must be type {}.".format(name, data_type)) from exc + return str(output) + + def serialize_data(self, data, data_type, **kwargs): + """Serialize generic data according to supplied data type. + + :param object data: The data to be serialized. + :param str data_type: The type to be serialized from. + :raises AttributeError: if required data is None. + :raises ValueError: if data is None + :raises SerializationError: if serialization fails. + :returns: The serialized data. + :rtype: str, int, float, bool, dict, list + """ + if data is None: + raise ValueError("No value for given attribute") + + try: + if data is CoreNull: + return None + if data_type in self.basic_types.values(): + return self.serialize_basic(data, data_type, **kwargs) + + if data_type in self.serialize_type: + return self.serialize_type[data_type](data, **kwargs) + + # If dependencies is empty, try with current data class + # It has to be a subclass of Enum anyway + enum_type = self.dependencies.get(data_type, data.__class__) + if issubclass(enum_type, Enum): + return Serializer.serialize_enum(data, enum_obj=enum_type) + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.serialize_type: + return self.serialize_type[iter_type](data, data_type[1:-1], **kwargs) + + except (ValueError, TypeError) as err: + msg = "Unable to serialize value: {!r} as type: {!r}." + raise SerializationError(msg.format(data, data_type)) from err + return self._serialize(data, **kwargs) + + @classmethod + def _get_custom_serializers(cls, data_type, **kwargs): # pylint: disable=inconsistent-return-statements + custom_serializer = kwargs.get("basic_types_serializers", {}).get(data_type) + if custom_serializer: + return custom_serializer + if kwargs.get("is_xml", False): + return cls._xml_basic_types_serializers.get(data_type) + + @classmethod + def serialize_basic(cls, data, data_type, **kwargs): + """Serialize basic builting data type. + Serializes objects to str, int, float or bool. + + Possible kwargs: + - basic_types_serializers dict[str, callable] : If set, use the callable as serializer + - is_xml bool : If set, use xml_basic_types_serializers + + :param obj data: Object to be serialized. + :param str data_type: Type of object in the iterable. + :rtype: str, int, float, bool + :return: serialized object + """ + custom_serializer = cls._get_custom_serializers(data_type, **kwargs) + if custom_serializer: + return custom_serializer(data) + if data_type == "str": + return cls.serialize_unicode(data) + return eval(data_type)(data) # nosec # pylint: disable=eval-used + + @classmethod + def serialize_unicode(cls, data): + """Special handling for serializing unicode strings in Py2. + Encode to UTF-8 if unicode, otherwise handle as a str. + + :param str data: Object to be serialized. + :rtype: str + :return: serialized object + """ + try: # If I received an enum, return its value + return data.value + except AttributeError: + pass + + try: + if isinstance(data, unicode): # type: ignore + # Don't change it, JSON and XML ElementTree are totally able + # to serialize correctly u'' strings + return data + except NameError: + return str(data) + return str(data) + + def serialize_iter(self, data, iter_type, div=None, **kwargs): + """Serialize iterable. + + Supported kwargs: + - serialization_ctxt dict : The current entry of _attribute_map, or same format. + serialization_ctxt['type'] should be same as data_type. + - is_xml bool : If set, serialize as XML + + :param list data: Object to be serialized. + :param str iter_type: Type of object in the iterable. + :param str div: If set, this str will be used to combine the elements + in the iterable into a combined string. Default is 'None'. + Defaults to False. + :rtype: list, str + :return: serialized iterable + """ + if isinstance(data, str): + raise SerializationError("Refuse str type as a valid iter type.") + + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + is_xml = kwargs.get("is_xml", False) + + serialized = [] + for d in data: + try: + serialized.append(self.serialize_data(d, iter_type, **kwargs)) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized.append(None) + + if kwargs.get("do_quote", False): + serialized = ["" if s is None else quote(str(s), safe="") for s in serialized] + + if div: + serialized = ["" if s is None else str(s) for s in serialized] + serialized = div.join(serialized) + + if "xml" in serialization_ctxt or is_xml: + # XML serialization is more complicated + xml_desc = serialization_ctxt.get("xml", {}) + xml_name = xml_desc.get("name") + if not xml_name: + xml_name = serialization_ctxt["key"] + + # Create a wrap node if necessary (use the fact that Element and list have "append") + is_wrapped = xml_desc.get("wrapped", False) + node_name = xml_desc.get("itemsName", xml_name) + if is_wrapped: + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + else: + final_result = [] + # All list elements to "local_node" + for el in serialized: + if isinstance(el, ET.Element): + el_node = el + else: + el_node = _create_xml_node(node_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + if el is not None: # Otherwise it writes "None" :-p + el_node.text = str(el) + final_result.append(el_node) + return final_result + return serialized + + def serialize_dict(self, attr, dict_type, **kwargs): + """Serialize a dictionary of objects. + + :param dict attr: Object to be serialized. + :param str dict_type: Type of object in the dictionary. + :rtype: dict + :return: serialized dictionary + """ + serialization_ctxt = kwargs.get("serialization_ctxt", {}) + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_data(value, dict_type, **kwargs) + except ValueError as err: + if isinstance(err, SerializationError): + raise + serialized[self.serialize_unicode(key)] = None + + if "xml" in serialization_ctxt: + # XML serialization is more complicated + xml_desc = serialization_ctxt["xml"] + xml_name = xml_desc["name"] + + final_result = _create_xml_node(xml_name, xml_desc.get("prefix", None), xml_desc.get("ns", None)) + for key, value in serialized.items(): + ET.SubElement(final_result, key).text = value + return final_result + + return serialized + + def serialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Serialize a generic object. + This will be handled as a dictionary. If object passed in is not + a basic type (str, int, float, dict, list) it will simply be + cast to str. + + :param dict attr: Object to be serialized. + :rtype: dict or str + :return: serialized object + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + return attr + obj_type = type(attr) + if obj_type in self.basic_types: + return self.serialize_basic(attr, self.basic_types[obj_type], **kwargs) + if obj_type is _long_type: + return self.serialize_long(attr) + if obj_type is str: + return self.serialize_unicode(attr) + if obj_type is datetime.datetime: + return self.serialize_iso(attr) + if obj_type is datetime.date: + return self.serialize_date(attr) + if obj_type is datetime.time: + return self.serialize_time(attr) + if obj_type is datetime.timedelta: + return self.serialize_duration(attr) + if obj_type is decimal.Decimal: + return self.serialize_decimal(attr) + + # If it's a model or I know this dependency, serialize as a Model + if obj_type in self.dependencies.values() or isinstance(attr, Model): + return self._serialize(attr) + + if obj_type == dict: + serialized = {} + for key, value in attr.items(): + try: + serialized[self.serialize_unicode(key)] = self.serialize_object(value, **kwargs) + except ValueError: + serialized[self.serialize_unicode(key)] = None + return serialized + + if obj_type == list: + serialized = [] + for obj in attr: + try: + serialized.append(self.serialize_object(obj, **kwargs)) + except ValueError: + pass + return serialized + return str(attr) + + @staticmethod + def serialize_enum(attr, enum_obj=None): + try: + result = attr.value + except AttributeError: + result = attr + try: + enum_obj(result) # type: ignore + return result + except ValueError as exc: + for enum_value in enum_obj: # type: ignore + if enum_value.value.lower() == str(attr).lower(): + return enum_value.value + error = "{!r} is not valid value for enum {!r}" + raise SerializationError(error.format(attr, enum_obj)) from exc + + @staticmethod + def serialize_bytearray(attr, **kwargs): # pylint: disable=unused-argument + """Serialize bytearray into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + return b64encode(attr).decode() + + @staticmethod + def serialize_base64(attr, **kwargs): # pylint: disable=unused-argument + """Serialize str into base-64 string. + + :param str attr: Object to be serialized. + :rtype: str + :return: serialized base64 + """ + encoded = b64encode(attr).decode("ascii") + return encoded.strip("=").replace("+", "-").replace("/", "_") + + @staticmethod + def serialize_decimal(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Decimal object to float. + + :param decimal attr: Object to be serialized. + :rtype: float + :return: serialized decimal + """ + return float(attr) + + @staticmethod + def serialize_long(attr, **kwargs): # pylint: disable=unused-argument + """Serialize long (Py2) or int (Py3). + + :param int attr: Object to be serialized. + :rtype: int/long + :return: serialized long + """ + return _long_type(attr) + + @staticmethod + def serialize_date(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Date object into ISO-8601 formatted string. + + :param Date attr: Object to be serialized. + :rtype: str + :return: serialized date + """ + if isinstance(attr, str): + attr = isodate.parse_date(attr) + t = "{:04}-{:02}-{:02}".format(attr.year, attr.month, attr.day) + return t + + @staticmethod + def serialize_time(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Time object into ISO-8601 formatted string. + + :param datetime.time attr: Object to be serialized. + :rtype: str + :return: serialized time + """ + if isinstance(attr, str): + attr = isodate.parse_time(attr) + t = "{:02}:{:02}:{:02}".format(attr.hour, attr.minute, attr.second) + if attr.microsecond: + t += ".{:02}".format(attr.microsecond) + return t + + @staticmethod + def serialize_duration(attr, **kwargs): # pylint: disable=unused-argument + """Serialize TimeDelta object into ISO-8601 formatted string. + + :param TimeDelta attr: Object to be serialized. + :rtype: str + :return: serialized duration + """ + if isinstance(attr, str): + attr = isodate.parse_duration(attr) + return isodate.duration_isoformat(attr) + + @staticmethod + def serialize_rfc(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into RFC-1123 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises TypeError: if format invalid. + :return: serialized rfc + """ + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + except AttributeError as exc: + raise TypeError("RFC1123 object must be valid Datetime object.") from exc + + return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format( + Serializer.days[utc.tm_wday], + utc.tm_mday, + Serializer.months[utc.tm_mon], + utc.tm_year, + utc.tm_hour, + utc.tm_min, + utc.tm_sec, + ) + + @staticmethod + def serialize_iso(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises SerializationError: if format invalid. + :return: serialized iso + """ + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + microseconds = str(attr.microsecond).rjust(6, "0").rstrip("0").ljust(3, "0") + if microseconds: + microseconds = "." + microseconds + date = "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}".format( + utc.tm_year, utc.tm_mon, utc.tm_mday, utc.tm_hour, utc.tm_min, utc.tm_sec + ) + return date + microseconds + "Z" + except (ValueError, OverflowError) as err: + msg = "Unable to serialize datetime object." + raise SerializationError(msg) from err + except AttributeError as err: + msg = "ISO-8601 object must be valid Datetime object." + raise TypeError(msg) from err + + @staticmethod + def serialize_unix(attr, **kwargs): # pylint: disable=unused-argument + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param Datetime attr: Object to be serialized. + :rtype: int + :raises SerializationError: if format invalid + :return: serialied unix + """ + if isinstance(attr, int): + return attr + try: + if not attr.tzinfo: + _LOGGER.warning("Datetime with no tzinfo will be considered UTC.") + return int(calendar.timegm(attr.utctimetuple())) + except AttributeError as exc: + raise TypeError("Unix time object must be valid Datetime object.") from exc + + +def rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + key = attr_desc["key"] + working_data = data + + while "." in key: + # Need the cast, as for some reasons "split" is typed as list[str | Any] + dict_keys = cast(List[str], _FLATTEN.split(key)) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = working_data.get(working_key, data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + return working_data.get(key) + + +def rest_key_case_insensitive_extractor( # pylint: disable=unused-argument, inconsistent-return-statements + attr, attr_desc, data +): + key = attr_desc["key"] + working_data = data + + while "." in key: + dict_keys = _FLATTEN.split(key) + if len(dict_keys) == 1: + key = _decode_attribute_map_key(dict_keys[0]) + break + working_key = _decode_attribute_map_key(dict_keys[0]) + working_data = attribute_key_case_insensitive_extractor(working_key, None, working_data) + if working_data is None: + # If at any point while following flatten JSON path see None, it means + # that all properties under are None as well + return None + key = ".".join(dict_keys[1:]) + + if working_data: + return attribute_key_case_insensitive_extractor(key, None, working_data) + + +def last_rest_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_extractor(dict_keys[-1], None, data) + + +def last_rest_key_case_insensitive_extractor(attr, attr_desc, data): # pylint: disable=unused-argument + """Extract the attribute in "data" based on the last part of the JSON path key. + + This is the case insensitive version of "last_rest_key_extractor" + :param str attr: The attribute to extract + :param dict attr_desc: The attribute description + :param dict data: The data to extract from + :rtype: object + :returns: The extracted attribute + """ + key = attr_desc["key"] + dict_keys = _FLATTEN.split(key) + return attribute_key_case_insensitive_extractor(dict_keys[-1], None, data) + + +def attribute_key_extractor(attr, _, data): + return data.get(attr) + + +def attribute_key_case_insensitive_extractor(attr, _, data): + found_key = None + lower_attr = attr.lower() + for key in data: + if lower_attr == key.lower(): + found_key = key + break + + return data.get(found_key) + + +def _extract_name_from_internal_type(internal_type): + """Given an internal type XML description, extract correct XML name with namespace. + + :param dict internal_type: An model type + :rtype: tuple + :returns: A tuple XML name + namespace dict + """ + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + xml_name = internal_type_xml_map.get("name", internal_type.__name__) + xml_ns = internal_type_xml_map.get("ns", None) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + return xml_name + + +def xml_key_extractor(attr, attr_desc, data): # pylint: disable=unused-argument,too-many-return-statements + if isinstance(data, dict): + return None + + # Test if this model is XML ready first + if not isinstance(data, ET.Element): + return None + + xml_desc = attr_desc.get("xml", {}) + xml_name = xml_desc.get("name", attr_desc["key"]) + + # Look for a children + is_iter_type = attr_desc["type"].startswith("[") + is_wrapped = xml_desc.get("wrapped", False) + internal_type = attr_desc.get("internalType", None) + internal_type_xml_map = getattr(internal_type, "_xml_map", {}) + + # Integrate namespace if necessary + xml_ns = xml_desc.get("ns", internal_type_xml_map.get("ns", None)) + if xml_ns: + xml_name = "{{{}}}{}".format(xml_ns, xml_name) + + # If it's an attribute, that's simple + if xml_desc.get("attr", False): + return data.get(xml_name) + + # If it's x-ms-text, that's simple too + if xml_desc.get("text", False): + return data.text + + # Scenario where I take the local name: + # - Wrapped node + # - Internal type is an enum (considered basic types) + # - Internal type has no XML/Name node + if is_wrapped or (internal_type and (issubclass(internal_type, Enum) or "name" not in internal_type_xml_map)): + children = data.findall(xml_name) + # If internal type has a local name and it's not a list, I use that name + elif not is_iter_type and internal_type and "name" in internal_type_xml_map: + xml_name = _extract_name_from_internal_type(internal_type) + children = data.findall(xml_name) + # That's an array + else: + if internal_type: # Complex type, ignore itemsName and use the complex type name + items_name = _extract_name_from_internal_type(internal_type) + else: + items_name = xml_desc.get("itemsName", xml_name) + children = data.findall(items_name) + + if len(children) == 0: + if is_iter_type: + if is_wrapped: + return None # is_wrapped no node, we want None + return [] # not wrapped, assume empty list + return None # Assume it's not there, maybe an optional node. + + # If is_iter_type and not wrapped, return all found children + if is_iter_type: + if not is_wrapped: + return children + # Iter and wrapped, should have found one node only (the wrap one) + if len(children) != 1: + raise DeserializationError( + "Tried to deserialize an array not wrapped, and found several nodes '{}'. Maybe you should declare this array as wrapped?".format( # pylint: disable=line-too-long + xml_name + ) + ) + return list(children[0]) # Might be empty list and that's ok. + + # Here it's not a itertype, we should have found one element only or empty + if len(children) > 1: + raise DeserializationError("Find several XML '{}' where it was not expected".format(xml_name)) + return children[0] + + +class Deserializer: + """Response object model deserializer. + + :param dict classes: Class type dictionary for deserializing complex types. + :ivar list key_extractors: Ordered list of extractors to be used by this deserializer. + """ + + basic_types = {str: "str", int: "int", bool: "bool", float: "float"} + + valid_date = re.compile(r"\d{4}[-]\d{2}[-]\d{2}T\d{2}:\d{2}:\d{2}\.?\d*Z?[-+]?[\d{2}]?:?[\d{2}]?") + + def __init__(self, classes: Optional[Mapping[str, type]] = None) -> None: + self.deserialize_type = { + "iso-8601": Deserializer.deserialize_iso, + "rfc-1123": Deserializer.deserialize_rfc, + "unix-time": Deserializer.deserialize_unix, + "duration": Deserializer.deserialize_duration, + "date": Deserializer.deserialize_date, + "time": Deserializer.deserialize_time, + "decimal": Deserializer.deserialize_decimal, + "long": Deserializer.deserialize_long, + "bytearray": Deserializer.deserialize_bytearray, + "base64": Deserializer.deserialize_base64, + "object": self.deserialize_object, + "[]": self.deserialize_iter, + "{}": self.deserialize_dict, + } + self.deserialize_expected_types = { + "duration": (isodate.Duration, datetime.timedelta), + "iso-8601": (datetime.datetime), + } + self.dependencies: Dict[str, type] = dict(classes) if classes else {} + self.key_extractors = [rest_key_extractor, xml_key_extractor] + # Additional properties only works if the "rest_key_extractor" is used to + # extract the keys. Making it to work whatever the key extractor is too much + # complicated, with no real scenario for now. + # So adding a flag to disable additional properties detection. This flag should be + # used if your expect the deserialization to NOT come from a JSON REST syntax. + # Otherwise, result are unexpected + self.additional_properties_detection = True + + def __call__(self, target_obj, response_data, content_type=None): + """Call the deserializer to process a REST response. + + :param str target_obj: Target data type to deserialize to. + :param requests.Response response_data: REST response object. + :param str content_type: Swagger "produces" if available. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + data = self._unpack_content(response_data, content_type) + return self._deserialize(target_obj, data) + + def _deserialize(self, target_obj, data): # pylint: disable=inconsistent-return-statements + """Call the deserializer on a model. + + Data needs to be already deserialized as JSON or XML ElementTree + + :param str target_obj: Target data type to deserialize to. + :param object data: Object to deserialize. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + # This is already a model, go recursive just in case + if hasattr(data, "_attribute_map"): + constants = [name for name, config in getattr(data, "_validation", {}).items() if config.get("constant")] + try: + for attr, mapconfig in data._attribute_map.items(): # pylint: disable=protected-access + if attr in constants: + continue + value = getattr(data, attr) + if value is None: + continue + local_type = mapconfig["type"] + internal_data_type = local_type.strip("[]{}") + if internal_data_type not in self.dependencies or isinstance(internal_data_type, Enum): + continue + setattr(data, attr, self._deserialize(local_type, value)) + return data + except AttributeError: + return + + response, class_name = self._classify_target(target_obj, data) + + if isinstance(response, str): + return self.deserialize_data(data, response) + if isinstance(response, type) and issubclass(response, Enum): + return self.deserialize_enum(data, response) + + if data is None or data is CoreNull: + return data + try: + attributes = response._attribute_map # type: ignore # pylint: disable=protected-access + d_attrs = {} + for attr, attr_desc in attributes.items(): + # Check empty string. If it's not empty, someone has a real "additionalProperties"... + if attr == "additional_properties" and attr_desc["key"] == "": + continue + raw_value = None + # Enhance attr_desc with some dynamic data + attr_desc = attr_desc.copy() # Do a copy, do not change the real one + internal_data_type = attr_desc["type"].strip("[]{}") + if internal_data_type in self.dependencies: + attr_desc["internalType"] = self.dependencies[internal_data_type] + + for key_extractor in self.key_extractors: + found_value = key_extractor(attr, attr_desc, data) + if found_value is not None: + if raw_value is not None and raw_value != found_value: + msg = ( + "Ignoring extracted value '%s' from %s for key '%s'" + " (duplicate extraction, follow extractors order)" + ) + _LOGGER.warning(msg, found_value, key_extractor, attr) + continue + raw_value = found_value + + value = self.deserialize_data(raw_value, attr_desc["type"]) + d_attrs[attr] = value + except (AttributeError, TypeError, KeyError) as err: + msg = "Unable to deserialize to object: " + class_name # type: ignore + raise DeserializationError(msg) from err + additional_properties = self._build_additional_properties(attributes, data) + return self._instantiate_model(response, d_attrs, additional_properties) + + def _build_additional_properties(self, attribute_map, data): + if not self.additional_properties_detection: + return None + if "additional_properties" in attribute_map and attribute_map.get("additional_properties", {}).get("key") != "": + # Check empty string. If it's not empty, someone has a real "additionalProperties" + return None + if isinstance(data, ET.Element): + data = {el.tag: el.text for el in data} + + known_keys = { + _decode_attribute_map_key(_FLATTEN.split(desc["key"])[0]) + for desc in attribute_map.values() + if desc["key"] != "" + } + present_keys = set(data.keys()) + missing_keys = present_keys - known_keys + return {key: data[key] for key in missing_keys} + + def _classify_target(self, target, data): + """Check to see whether the deserialization target object can + be classified into a subclass. + Once classification has been determined, initialize object. + + :param str target: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :return: The classified target object and its class name. + :rtype: tuple + """ + if target is None: + return None, None + + if isinstance(target, str): + try: + target = self.dependencies[target] + except KeyError: + return target, target + + try: + target = target._classify(data, self.dependencies) # type: ignore # pylint: disable=protected-access + except AttributeError: + pass # Target is not a Model, no classify + return target, target.__class__.__name__ # type: ignore + + def failsafe_deserialize(self, target_obj, data, content_type=None): + """Ignores any errors encountered in deserialization, + and falls back to not deserializing the object. Recommended + for use in error deserialization, as we want to return the + HttpResponseError to users, and not have them deal with + a deserialization error. + + :param str target_obj: The target object type to deserialize to. + :param str/dict data: The response data to deserialize. + :param str content_type: Swagger "produces" if available. + :return: Deserialized object. + :rtype: object + """ + try: + return self(target_obj, data, content_type=content_type) + except: # pylint: disable=bare-except + _LOGGER.debug( + "Ran into a deserialization error. Ignoring since this is failsafe deserialization", exc_info=True + ) + return None + + @staticmethod + def _unpack_content(raw_data, content_type=None): + """Extract the correct structure for deserialization. + + If raw_data is a PipelineResponse, try to extract the result of RawDeserializer. + if we can't, raise. Your Pipeline should have a RawDeserializer. + + If not a pipeline response and raw_data is bytes or string, use content-type + to decode it. If no content-type, try JSON. + + If raw_data is something else, bypass all logic and return it directly. + + :param obj raw_data: Data to be processed. + :param str content_type: How to parse if raw_data is a string/bytes. + :raises JSONDecodeError: If JSON is requested and parsing is impossible. + :raises UnicodeDecodeError: If bytes is not UTF8 + :rtype: object + :return: Unpacked content. + """ + # Assume this is enough to detect a Pipeline Response without importing it + context = getattr(raw_data, "context", {}) + if context: + if RawDeserializer.CONTEXT_NAME in context: + return context[RawDeserializer.CONTEXT_NAME] + raise ValueError("This pipeline didn't have the RawDeserializer policy; can't deserialize") + + # Assume this is enough to recognize universal_http.ClientResponse without importing it + if hasattr(raw_data, "body"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text(), raw_data.headers) + + # Assume this enough to recognize requests.Response without importing it. + if hasattr(raw_data, "_content_consumed"): + return RawDeserializer.deserialize_from_http_generics(raw_data.text, raw_data.headers) + + if isinstance(raw_data, (str, bytes)) or hasattr(raw_data, "read"): + return RawDeserializer.deserialize_from_text(raw_data, content_type) # type: ignore + return raw_data + + def _instantiate_model(self, response, attrs, additional_properties=None): + """Instantiate a response model passing in deserialized args. + + :param Response response: The response model class. + :param dict attrs: The deserialized response attributes. + :param dict additional_properties: Additional properties to be set. + :rtype: Response + :return: The instantiated response model. + """ + if callable(response): + subtype = getattr(response, "_subtype_map", {}) + try: + readonly = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("readonly") + ] + const = [ + k + for k, v in response._validation.items() # pylint: disable=protected-access # type: ignore + if v.get("constant") + ] + kwargs = {k: v for k, v in attrs.items() if k not in subtype and k not in readonly + const} + response_obj = response(**kwargs) + for attr in readonly: + setattr(response_obj, attr, attrs.get(attr)) + if additional_properties: + response_obj.additional_properties = additional_properties # type: ignore + return response_obj + except TypeError as err: + msg = "Unable to deserialize {} into model {}. ".format(kwargs, response) # type: ignore + raise DeserializationError(msg + str(err)) from err + else: + try: + for attr, value in attrs.items(): + setattr(response, attr, value) + return response + except Exception as exp: + msg = "Unable to populate response model. " + msg += "Type: {}, Error: {}".format(type(response), exp) + raise DeserializationError(msg) from exp + + def deserialize_data(self, data, data_type): # pylint: disable=too-many-return-statements + """Process data for deserialization according to data type. + + :param str data: The response string to be deserialized. + :param str data_type: The type to deserialize to. + :raises DeserializationError: if deserialization fails. + :return: Deserialized object. + :rtype: object + """ + if data is None: + return data + + try: + if not data_type: + return data + if data_type in self.basic_types.values(): + return self.deserialize_basic(data, data_type) + if data_type in self.deserialize_type: + if isinstance(data, self.deserialize_expected_types.get(data_type, tuple())): + return data + + is_a_text_parsing_type = lambda x: x not in [ # pylint: disable=unnecessary-lambda-assignment + "object", + "[]", + r"{}", + ] + if isinstance(data, ET.Element) and is_a_text_parsing_type(data_type) and not data.text: + return None + data_val = self.deserialize_type[data_type](data) + return data_val + + iter_type = data_type[0] + data_type[-1] + if iter_type in self.deserialize_type: + return self.deserialize_type[iter_type](data, data_type[1:-1]) + + obj_type = self.dependencies[data_type] + if issubclass(obj_type, Enum): + if isinstance(data, ET.Element): + data = data.text + return self.deserialize_enum(data, obj_type) + + except (ValueError, TypeError, AttributeError) as err: + msg = "Unable to deserialize response data." + msg += " Data: {}, {}".format(data, data_type) + raise DeserializationError(msg) from err + return self._deserialize(obj_type, data) + + def deserialize_iter(self, attr, iter_type): + """Deserialize an iterable. + + :param list attr: Iterable to be deserialized. + :param str iter_type: The type of object in the iterable. + :return: Deserialized iterable. + :rtype: list + """ + if attr is None: + return None + if isinstance(attr, ET.Element): # If I receive an element here, get the children + attr = list(attr) + if not isinstance(attr, (list, set)): + raise DeserializationError("Cannot deserialize as [{}] an object of type {}".format(iter_type, type(attr))) + return [self.deserialize_data(a, iter_type) for a in attr] + + def deserialize_dict(self, attr, dict_type): + """Deserialize a dictionary. + + :param dict/list attr: Dictionary to be deserialized. Also accepts + a list of key, value pairs. + :param str dict_type: The object type of the items in the dictionary. + :return: Deserialized dictionary. + :rtype: dict + """ + if isinstance(attr, list): + return {x["key"]: self.deserialize_data(x["value"], dict_type) for x in attr} + + if isinstance(attr, ET.Element): + # Transform <Key>value</Key> into {"Key": "value"} + attr = {el.tag: el.text for el in attr} + return {k: self.deserialize_data(v, dict_type) for k, v in attr.items()} + + def deserialize_object(self, attr, **kwargs): # pylint: disable=too-many-return-statements + """Deserialize a generic object. + This will be handled as a dictionary. + + :param dict attr: Dictionary to be deserialized. + :return: Deserialized object. + :rtype: dict + :raises TypeError: if non-builtin datatype encountered. + """ + if attr is None: + return None + if isinstance(attr, ET.Element): + # Do no recurse on XML, just return the tree as-is + return attr + if isinstance(attr, str): + return self.deserialize_basic(attr, "str") + obj_type = type(attr) + if obj_type in self.basic_types: + return self.deserialize_basic(attr, self.basic_types[obj_type]) + if obj_type is _long_type: + return self.deserialize_long(attr) + + if obj_type == dict: + deserialized = {} + for key, value in attr.items(): + try: + deserialized[key] = self.deserialize_object(value, **kwargs) + except ValueError: + deserialized[key] = None + return deserialized + + if obj_type == list: + deserialized = [] + for obj in attr: + try: + deserialized.append(self.deserialize_object(obj, **kwargs)) + except ValueError: + pass + return deserialized + + error = "Cannot deserialize generic object with type: " + raise TypeError(error + str(obj_type)) + + def deserialize_basic(self, attr, data_type): # pylint: disable=too-many-return-statements + """Deserialize basic builtin data type from string. + Will attempt to convert to str, int, float and bool. + This function will also accept '1', '0', 'true' and 'false' as + valid bool values. + + :param str attr: response string to be deserialized. + :param str data_type: deserialization data type. + :return: Deserialized basic type. + :rtype: str, int, float or bool + :raises TypeError: if string format is not valid. + """ + # If we're here, data is supposed to be a basic type. + # If it's still an XML node, take the text + if isinstance(attr, ET.Element): + attr = attr.text + if not attr: + if data_type == "str": + # None or '', node <a/> is empty string. + return "" + # None or '', node <a/> with a strong type is None. + # Don't try to model "empty bool" or "empty int" + return None + + if data_type == "bool": + if attr in [True, False, 1, 0]: + return bool(attr) + if isinstance(attr, str): + if attr.lower() in ["true", "1"]: + return True + if attr.lower() in ["false", "0"]: + return False + raise TypeError("Invalid boolean value: {}".format(attr)) + + if data_type == "str": + return self.deserialize_unicode(attr) + return eval(data_type)(attr) # nosec # pylint: disable=eval-used + + @staticmethod + def deserialize_unicode(data): + """Preserve unicode objects in Python 2, otherwise return data + as a string. + + :param str data: response string to be deserialized. + :return: Deserialized string. + :rtype: str or unicode + """ + # We might be here because we have an enum modeled as string, + # and we try to deserialize a partial dict with enum inside + if isinstance(data, Enum): + return data + + # Consider this is real string + try: + if isinstance(data, unicode): # type: ignore + return data + except NameError: + return str(data) + return str(data) + + @staticmethod + def deserialize_enum(data, enum_obj): + """Deserialize string into enum object. + + If the string is not a valid enum value it will be returned as-is + and a warning will be logged. + + :param str data: Response string to be deserialized. If this value is + None or invalid it will be returned as-is. + :param Enum enum_obj: Enum object to deserialize to. + :return: Deserialized enum object. + :rtype: Enum + """ + if isinstance(data, enum_obj) or data is None: + return data + if isinstance(data, Enum): + data = data.value + if isinstance(data, int): + # Workaround. We might consider remove it in the future. + try: + return list(enum_obj.__members__.values())[data] + except IndexError as exc: + error = "{!r} is not a valid index for enum {!r}" + raise DeserializationError(error.format(data, enum_obj)) from exc + try: + return enum_obj(str(data)) + except ValueError: + for enum_value in enum_obj: + if enum_value.value.lower() == str(data).lower(): + return enum_value + # We don't fail anymore for unknown value, we deserialize as a string + _LOGGER.warning("Deserializer is not able to find %s as valid enum in %s", data, enum_obj) + return Deserializer.deserialize_unicode(data) + + @staticmethod + def deserialize_bytearray(attr): + """Deserialize string into bytearray. + + :param str attr: response string to be deserialized. + :return: Deserialized bytearray + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return bytearray(b64decode(attr)) # type: ignore + + @staticmethod + def deserialize_base64(attr): + """Deserialize base64 encoded string into string. + + :param str attr: response string to be deserialized. + :return: Deserialized base64 string + :rtype: bytearray + :raises TypeError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + padding = "=" * (3 - (len(attr) + 3) % 4) # type: ignore + attr = attr + padding # type: ignore + encoded = attr.replace("-", "+").replace("_", "/") + return b64decode(encoded) + + @staticmethod + def deserialize_decimal(attr): + """Deserialize string into Decimal object. + + :param str attr: response string to be deserialized. + :return: Deserialized decimal + :raises DeserializationError: if string format invalid. + :rtype: decimal + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + return decimal.Decimal(str(attr)) # type: ignore + except decimal.DecimalException as err: + msg = "Invalid decimal {}".format(attr) + raise DeserializationError(msg) from err + + @staticmethod + def deserialize_long(attr): + """Deserialize string into long (Py2) or int (Py3). + + :param str attr: response string to be deserialized. + :return: Deserialized int + :rtype: long or int + :raises ValueError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + return _long_type(attr) # type: ignore + + @staticmethod + def deserialize_duration(attr): + """Deserialize ISO-8601 formatted string into TimeDelta object. + + :param str attr: response string to be deserialized. + :return: Deserialized duration + :rtype: TimeDelta + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + duration = isodate.parse_duration(attr) + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize duration object." + raise DeserializationError(msg) from err + return duration + + @staticmethod + def deserialize_date(attr): + """Deserialize ISO-8601 formatted string into Date object. + + :param str attr: response string to be deserialized. + :return: Deserialized date + :rtype: Date + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + # This must NOT use defaultmonth/defaultday. Using None ensure this raises an exception. + return isodate.parse_date(attr, defaultmonth=0, defaultday=0) + + @staticmethod + def deserialize_time(attr): + """Deserialize ISO-8601 formatted string into time object. + + :param str attr: response string to be deserialized. + :return: Deserialized time + :rtype: datetime.time + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + if re.search(r"[^\W\d_]", attr, re.I + re.U): # type: ignore + raise DeserializationError("Date must have only digits and -. Received: %s" % attr) + return isodate.parse_time(attr) + + @staticmethod + def deserialize_rfc(attr): + """Deserialize RFC-1123 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized RFC datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + parsed_date = email.utils.parsedate_tz(attr) # type: ignore + date_obj = datetime.datetime( + *parsed_date[:6], tzinfo=datetime.timezone(datetime.timedelta(minutes=(parsed_date[9] or 0) / 60)) + ) + if not date_obj.tzinfo: + date_obj = date_obj.astimezone(tz=TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to rfc datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_iso(attr): + """Deserialize ISO-8601 formatted string into Datetime object. + + :param str attr: response string to be deserialized. + :return: Deserialized ISO datetime + :rtype: Datetime + :raises DeserializationError: if string format invalid. + """ + if isinstance(attr, ET.Element): + attr = attr.text + try: + attr = attr.upper() # type: ignore + match = Deserializer.valid_date.match(attr) + if not match: + raise ValueError("Invalid datetime string: " + attr) + + check_decimal = attr.split(".") + if len(check_decimal) > 1: + decimal_str = "" + for digit in check_decimal[1]: + if digit.isdigit(): + decimal_str += digit + else: + break + if len(decimal_str) > 6: + attr = attr.replace(decimal_str, decimal_str[0:6]) + + date_obj = isodate.parse_datetime(attr) + test_utc = date_obj.utctimetuple() + if test_utc.tm_year > 9999 or test_utc.tm_year < 1: + raise OverflowError("Hit max or min date") + except (ValueError, OverflowError, AttributeError) as err: + msg = "Cannot deserialize datetime object." + raise DeserializationError(msg) from err + return date_obj + + @staticmethod + def deserialize_unix(attr): + """Serialize Datetime object into IntTime format. + This is represented as seconds. + + :param int attr: Object to be serialized. + :return: Deserialized datetime + :rtype: Datetime + :raises DeserializationError: if format invalid + """ + if isinstance(attr, ET.Element): + attr = int(attr.text) # type: ignore + try: + attr = int(attr) + date_obj = datetime.datetime.fromtimestamp(attr, TZ_UTC) + except ValueError as err: + msg = "Cannot deserialize to unix datetime object." + raise DeserializationError(msg) from err + return date_obj diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/__init__.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/__init__.py new file mode 100644 index 00000000..b4f1dd31 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/__init__.py @@ -0,0 +1,29 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._azure_file_storage import AzureFileStorage # type: ignore + +try: + from ._patch import __all__ as _patch_all + from ._patch import * +except ImportError: + _patch_all = [] +from ._patch import patch_sdk as _patch_sdk + +__all__ = [ + "AzureFileStorage", +] +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore + +_patch_sdk() diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/_azure_file_storage.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/_azure_file_storage.py new file mode 100644 index 00000000..22c80eec --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/_azure_file_storage.py @@ -0,0 +1,132 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from copy import deepcopy +from typing import Any, Awaitable, Optional, Union +from typing_extensions import Self + +from azure.core import AsyncPipelineClient +from azure.core.pipeline import policies +from azure.core.rest import AsyncHttpResponse, HttpRequest + +from .. import models as _models +from .._serialization import Deserializer, Serializer +from ._configuration import AzureFileStorageConfiguration +from .operations import DirectoryOperations, FileOperations, ServiceOperations, ShareOperations + + +class AzureFileStorage: # pylint: disable=client-accepts-api-version-keyword + """AzureFileStorage. + + :ivar service: ServiceOperations operations + :vartype service: azure.storage.fileshare.aio.operations.ServiceOperations + :ivar share: ShareOperations operations + :vartype share: azure.storage.fileshare.aio.operations.ShareOperations + :ivar directory: DirectoryOperations operations + :vartype directory: azure.storage.fileshare.aio.operations.DirectoryOperations + :ivar file: FileOperations operations + :vartype file: azure.storage.fileshare.aio.operations.FileOperations + :param url: The URL of the service account, share, directory or file that is the target of the + desired operation. Required. + :type url: str + :param base_url: Service URL. Required. Default value is "". + :type base_url: str + :param file_request_intent: Valid value is backup. "backup" Default value is None. + :type file_request_intent: str or ~azure.storage.fileshare.models.ShareTokenIntent + :param allow_trailing_dot: If true, the trailing dot will not be trimmed from the target URI. + Default value is None. + :type allow_trailing_dot: bool + :param allow_source_trailing_dot: If true, the trailing dot will not be trimmed from the source + URI. Default value is None. + :type allow_source_trailing_dot: bool + :keyword version: Specifies the version of the operation to use for this request. Default value + is "2025-05-05". Note that overriding this default value may result in unsupported behavior. + :paramtype version: str + :keyword file_range_write_from_url: Only update is supported: - Update: Writes the bytes + downloaded from the source url into the specified range. Default value is "update". Note that + overriding this default value may result in unsupported behavior. + :paramtype file_range_write_from_url: str + """ + + def __init__( # pylint: disable=missing-client-constructor-parameter-credential + self, + url: str, + base_url: str = "", + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + allow_trailing_dot: Optional[bool] = None, + allow_source_trailing_dot: Optional[bool] = None, + **kwargs: Any + ) -> None: + self._config = AzureFileStorageConfiguration( + url=url, + file_request_intent=file_request_intent, + allow_trailing_dot=allow_trailing_dot, + allow_source_trailing_dot=allow_source_trailing_dot, + **kwargs + ) + _policies = kwargs.pop("policies", None) + if _policies is None: + _policies = [ + policies.RequestIdPolicy(**kwargs), + self._config.headers_policy, + self._config.user_agent_policy, + self._config.proxy_policy, + policies.ContentDecodePolicy(**kwargs), + self._config.redirect_policy, + self._config.retry_policy, + self._config.authentication_policy, + self._config.custom_hook_policy, + self._config.logging_policy, + policies.DistributedTracingPolicy(**kwargs), + policies.SensitiveHeaderCleanupPolicy(**kwargs) if self._config.redirect_policy else None, + self._config.http_logging_policy, + ] + self._client: AsyncPipelineClient = AsyncPipelineClient(base_url=base_url, policies=_policies, **kwargs) + + client_models = {k: v for k, v in _models.__dict__.items() if isinstance(v, type)} + self._serialize = Serializer(client_models) + self._deserialize = Deserializer(client_models) + self._serialize.client_side_validation = False + self.service = ServiceOperations(self._client, self._config, self._serialize, self._deserialize) + self.share = ShareOperations(self._client, self._config, self._serialize, self._deserialize) + self.directory = DirectoryOperations(self._client, self._config, self._serialize, self._deserialize) + self.file = FileOperations(self._client, self._config, self._serialize, self._deserialize) + + def _send_request( + self, request: HttpRequest, *, stream: bool = False, **kwargs: Any + ) -> Awaitable[AsyncHttpResponse]: + """Runs the network request through the client's chained policies. + + >>> from azure.core.rest import HttpRequest + >>> request = HttpRequest("GET", "https://www.example.org/") + <HttpRequest [GET], url: 'https://www.example.org/'> + >>> response = await client._send_request(request) + <AsyncHttpResponse: 200 OK> + + For more information on this code flow, see https://aka.ms/azsdk/dpcodegen/python/send_request + + :param request: The network request you want to make. Required. + :type request: ~azure.core.rest.HttpRequest + :keyword bool stream: Whether the response payload will be streamed. Defaults to False. + :return: The response of your network call. Does not do error handling on your response. + :rtype: ~azure.core.rest.AsyncHttpResponse + """ + + request_copy = deepcopy(request) + request_copy.url = self._client.format_url(request_copy.url) + return self._client.send_request(request_copy, stream=stream, **kwargs) # type: ignore + + async def close(self) -> None: + await self._client.close() + + async def __aenter__(self) -> Self: + await self._client.__aenter__() + return self + + async def __aexit__(self, *exc_details: Any) -> None: + await self._client.__aexit__(*exc_details) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/_configuration.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/_configuration.py new file mode 100644 index 00000000..7cc25f81 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/_configuration.py @@ -0,0 +1,77 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from typing import Any, Literal, Optional, Union + +from azure.core.pipeline import policies + +from .. import models as _models + +VERSION = "unknown" + + +class AzureFileStorageConfiguration: # pylint: disable=too-many-instance-attributes + """Configuration for AzureFileStorage. + + Note that all parameters used to create this instance are saved as instance + attributes. + + :param url: The URL of the service account, share, directory or file that is the target of the + desired operation. Required. + :type url: str + :param file_request_intent: Valid value is backup. "backup" Default value is None. + :type file_request_intent: str or ~azure.storage.fileshare.models.ShareTokenIntent + :param allow_trailing_dot: If true, the trailing dot will not be trimmed from the target URI. + Default value is None. + :type allow_trailing_dot: bool + :param allow_source_trailing_dot: If true, the trailing dot will not be trimmed from the source + URI. Default value is None. + :type allow_source_trailing_dot: bool + :keyword version: Specifies the version of the operation to use for this request. Default value + is "2025-05-05". Note that overriding this default value may result in unsupported behavior. + :paramtype version: str + :keyword file_range_write_from_url: Only update is supported: - Update: Writes the bytes + downloaded from the source url into the specified range. Default value is "update". Note that + overriding this default value may result in unsupported behavior. + :paramtype file_range_write_from_url: str + """ + + def __init__( + self, + url: str, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + allow_trailing_dot: Optional[bool] = None, + allow_source_trailing_dot: Optional[bool] = None, + **kwargs: Any + ) -> None: + version: Literal["2025-05-05"] = kwargs.pop("version", "2025-05-05") + file_range_write_from_url: Literal["update"] = kwargs.pop("file_range_write_from_url", "update") + + if url is None: + raise ValueError("Parameter 'url' must not be None.") + + self.url = url + self.file_request_intent = file_request_intent + self.allow_trailing_dot = allow_trailing_dot + self.allow_source_trailing_dot = allow_source_trailing_dot + self.version = version + self.file_range_write_from_url = file_range_write_from_url + kwargs.setdefault("sdk_moniker", "azurefilestorage/{}".format(VERSION)) + self.polling_interval = kwargs.get("polling_interval", 30) + self._configure(**kwargs) + + def _configure(self, **kwargs: Any) -> None: + self.user_agent_policy = kwargs.get("user_agent_policy") or policies.UserAgentPolicy(**kwargs) + self.headers_policy = kwargs.get("headers_policy") or policies.HeadersPolicy(**kwargs) + self.proxy_policy = kwargs.get("proxy_policy") or policies.ProxyPolicy(**kwargs) + self.logging_policy = kwargs.get("logging_policy") or policies.NetworkTraceLoggingPolicy(**kwargs) + self.http_logging_policy = kwargs.get("http_logging_policy") or policies.HttpLoggingPolicy(**kwargs) + self.custom_hook_policy = kwargs.get("custom_hook_policy") or policies.CustomHookPolicy(**kwargs) + self.redirect_policy = kwargs.get("redirect_policy") or policies.AsyncRedirectPolicy(**kwargs) + self.retry_policy = kwargs.get("retry_policy") or policies.AsyncRetryPolicy(**kwargs) + self.authentication_policy = kwargs.get("authentication_policy") diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/_patch.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/_patch.py new file mode 100644 index 00000000..f7dd3251 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/_patch.py @@ -0,0 +1,20 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Customize generated code here. + +Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize +""" +from typing import List + +__all__: List[str] = [] # Add all objects you want publicly available to users at this package level + + +def patch_sdk(): + """Do not remove from this file. + + `patch_sdk` is a last resort escape hatch that allows you to do customizations + you can't accomplish using the techniques described in + https://aka.ms/azsdk/python/dpcodegen/python/customize + """ diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/__init__.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/__init__.py new file mode 100644 index 00000000..092b7efd --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/__init__.py @@ -0,0 +1,31 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._service_operations import ServiceOperations # type: ignore +from ._share_operations import ShareOperations # type: ignore +from ._directory_operations import DirectoryOperations # type: ignore +from ._file_operations import FileOperations # type: ignore + +from ._patch import __all__ as _patch_all +from ._patch import * +from ._patch import patch_sdk as _patch_sdk + +__all__ = [ + "ServiceOperations", + "ShareOperations", + "DirectoryOperations", + "FileOperations", +] +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore +_patch_sdk() diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_directory_operations.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_directory_operations.py new file mode 100644 index 00000000..83a84985 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_directory_operations.py @@ -0,0 +1,1056 @@ +# pylint: disable=too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +import sys +from typing import Any, Callable, Dict, List, Literal, Optional, TypeVar, Union + +from azure.core import AsyncPipelineClient +from azure.core.exceptions import ( + ClientAuthenticationError, + HttpResponseError, + ResourceExistsError, + ResourceNotFoundError, + ResourceNotModifiedError, + map_error, +) +from azure.core.pipeline import PipelineResponse +from azure.core.rest import AsyncHttpResponse, HttpRequest +from azure.core.tracing.decorator_async import distributed_trace_async +from azure.core.utils import case_insensitive_dict + +from ... import models as _models +from ..._serialization import Deserializer, Serializer +from ...operations._directory_operations import ( + build_create_request, + build_delete_request, + build_force_close_handles_request, + build_get_properties_request, + build_list_files_and_directories_segment_request, + build_list_handles_request, + build_rename_request, + build_set_metadata_request, + build_set_properties_request, +) +from .._configuration import AzureFileStorageConfiguration + +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore +T = TypeVar("T") +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + + +class DirectoryOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.storage.fileshare.aio.AzureFileStorage`'s + :attr:`directory` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AzureFileStorageConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace_async + async def create( + self, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + file_attributes: str = "none", + file_creation_time: str = "now", + file_last_write_time: str = "now", + file_change_time: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Creates a new directory under the specified share or parent directory. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param file_attributes: If specified, the provided file attributes shall be set. Default value: + ‘Archive’ for file and ‘Directory’ for directory. ‘None’ can also be specified as default. + Default value is "none". + :type file_attributes: str + :param file_creation_time: Creation time for the file/directory. Default value: Now. Default + value is "now". + :type file_creation_time: str + :param file_last_write_time: Last write time for the file/directory. Default value: Now. + Default value is "now". + :type file_last_write_time: str + :param file_change_time: Change time for the file/directory. Default value: Now. Default value + is None. + :type file_change_time: str + :param owner: Optional, NFS only. The owner of the file or directory. Default value is None. + :type owner: str + :param group: Optional, NFS only. The owning group of the file or directory. Default value is + None. + :type group: str + :param file_mode: Optional, NFS only. The file mode of the file or directory. Default value is + None. + :type file_mode: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_create_request( + url=self._config.url, + timeout=timeout, + metadata=metadata, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + file_attributes=file_attributes, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + file_change_time=file_change_time, + owner=owner, + group=group, + file_mode=file_mode, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-file-file-type"] = self._deserialize("str", response.headers.get("x-ms-file-file-type")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def get_properties( + self, sharesnapshot: Optional[str] = None, timeout: Optional[int] = None, **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Returns all system properties for the specified directory, and can also be used to check the + existence of a directory. The data returned does not include the files in the directory or any + subdirectories. + + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_get_properties_request( + url=self._config.url, + sharesnapshot=sharesnapshot, + timeout=timeout, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-meta"] = self._deserialize("{str}", response.headers.get("x-ms-meta")) + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-server-encrypted") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-file-file-type"] = self._deserialize("str", response.headers.get("x-ms-file-file-type")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def delete(self, timeout: Optional[int] = None, **kwargs: Any) -> None: + # pylint: disable=line-too-long + """Removes the specified empty directory. Note that the directory must be empty before it can be + deleted. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_delete_request( + url=self._config.url, + timeout=timeout, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def set_properties( + self, + timeout: Optional[int] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + file_attributes: str = "none", + file_creation_time: str = "now", + file_last_write_time: str = "now", + file_change_time: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Sets properties on the directory. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param file_attributes: If specified, the provided file attributes shall be set. Default value: + ‘Archive’ for file and ‘Directory’ for directory. ‘None’ can also be specified as default. + Default value is "none". + :type file_attributes: str + :param file_creation_time: Creation time for the file/directory. Default value: Now. Default + value is "now". + :type file_creation_time: str + :param file_last_write_time: Last write time for the file/directory. Default value: Now. + Default value is "now". + :type file_last_write_time: str + :param file_change_time: Change time for the file/directory. Default value: Now. Default value + is None. + :type file_change_time: str + :param owner: Optional, NFS only. The owner of the file or directory. Default value is None. + :type owner: str + :param group: Optional, NFS only. The owning group of the file or directory. Default value is + None. + :type group: str + :param file_mode: Optional, NFS only. The file mode of the file or directory. Default value is + None. + :type file_mode: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_set_properties_request( + url=self._config.url, + timeout=timeout, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + file_attributes=file_attributes, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + file_change_time=file_change_time, + owner=owner, + group=group, + file_mode=file_mode, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def set_metadata( + self, timeout: Optional[int] = None, metadata: Optional[Dict[str, str]] = None, **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Updates user defined metadata for the specified directory. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + comp: Literal["metadata"] = kwargs.pop("comp", _params.pop("comp", "metadata")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_set_metadata_request( + url=self._config.url, + timeout=timeout, + metadata=metadata, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def list_files_and_directories_segment( + self, + prefix: Optional[str] = None, + sharesnapshot: Optional[str] = None, + marker: Optional[str] = None, + maxresults: Optional[int] = None, + timeout: Optional[int] = None, + include: Optional[List[Union[str, _models.ListFilesIncludeType]]] = None, + include_extended_info: Optional[bool] = None, + **kwargs: Any + ) -> _models.ListFilesAndDirectoriesSegmentResponse: + # pylint: disable=line-too-long + """Returns a list of files or directories under the specified share or directory. It lists the + contents only for a single level of the directory hierarchy. + + :param prefix: Filters the results to return only entries whose name begins with the specified + prefix. Default value is None. + :type prefix: str + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param marker: A string value that identifies the portion of the list to be returned with the + next list operation. The operation returns a marker value within the response body if the list + returned was not complete. The marker value may then be used in a subsequent call to request + the next set of list items. The marker value is opaque to the client. Default value is None. + :type marker: str + :param maxresults: Specifies the maximum number of entries to return. If the request does not + specify maxresults, or specifies a value greater than 5,000, the server will return up to 5,000 + items. Default value is None. + :type maxresults: int + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param include: Include this parameter to specify one or more datasets to include in the + response. Default value is None. + :type include: list[str or ~azure.storage.fileshare.models.ListFilesIncludeType] + :param include_extended_info: Include extended information. Default value is None. + :type include_extended_info: bool + :return: ListFilesAndDirectoriesSegmentResponse or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.ListFilesAndDirectoriesSegmentResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + comp: Literal["list"] = kwargs.pop("comp", _params.pop("comp", "list")) + cls: ClsType[_models.ListFilesAndDirectoriesSegmentResponse] = kwargs.pop("cls", None) + + _request = build_list_files_and_directories_segment_request( + url=self._config.url, + prefix=prefix, + sharesnapshot=sharesnapshot, + marker=marker, + maxresults=maxresults, + timeout=timeout, + include=include, + include_extended_info=include_extended_info, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("ListFilesAndDirectoriesSegmentResponse", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def list_handles( + self, + marker: Optional[str] = None, + maxresults: Optional[int] = None, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + recursive: Optional[bool] = None, + **kwargs: Any + ) -> _models.ListHandlesResponse: + # pylint: disable=line-too-long + """Lists handles for directory. + + :param marker: A string value that identifies the portion of the list to be returned with the + next list operation. The operation returns a marker value within the response body if the list + returned was not complete. The marker value may then be used in a subsequent call to request + the next set of list items. The marker value is opaque to the client. Default value is None. + :type marker: str + :param maxresults: Specifies the maximum number of entries to return. If the request does not + specify maxresults, or specifies a value greater than 5,000, the server will return up to 5,000 + items. Default value is None. + :type maxresults: int + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param recursive: Specifies operation should apply to the directory specified in the URI, its + files, its subdirectories and their files. Default value is None. + :type recursive: bool + :return: ListHandlesResponse or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.ListHandlesResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["listhandles"] = kwargs.pop("comp", _params.pop("comp", "listhandles")) + cls: ClsType[_models.ListHandlesResponse] = kwargs.pop("cls", None) + + _request = build_list_handles_request( + url=self._config.url, + marker=marker, + maxresults=maxresults, + timeout=timeout, + sharesnapshot=sharesnapshot, + recursive=recursive, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("ListHandlesResponse", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def force_close_handles( + self, + handle_id: str, + timeout: Optional[int] = None, + marker: Optional[str] = None, + sharesnapshot: Optional[str] = None, + recursive: Optional[bool] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Closes all handles open for given directory. + + :param handle_id: Specifies handle ID opened on the file or directory to be closed. Asterisk + (‘*’) is a wildcard that specifies all handles. Required. + :type handle_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param marker: A string value that identifies the portion of the list to be returned with the + next list operation. The operation returns a marker value within the response body if the list + returned was not complete. The marker value may then be used in a subsequent call to request + the next set of list items. The marker value is opaque to the client. Default value is None. + :type marker: str + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param recursive: Specifies operation should apply to the directory specified in the URI, its + files, its subdirectories and their files. Default value is None. + :type recursive: bool + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["forceclosehandles"] = kwargs.pop("comp", _params.pop("comp", "forceclosehandles")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_force_close_handles_request( + url=self._config.url, + handle_id=handle_id, + timeout=timeout, + marker=marker, + sharesnapshot=sharesnapshot, + recursive=recursive, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-marker"] = self._deserialize("str", response.headers.get("x-ms-marker")) + response_headers["x-ms-number-of-handles-closed"] = self._deserialize( + "int", response.headers.get("x-ms-number-of-handles-closed") + ) + response_headers["x-ms-number-of-handles-failed"] = self._deserialize( + "int", response.headers.get("x-ms-number-of-handles-failed") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def rename( + self, + rename_source: str, + timeout: Optional[int] = None, + replace_if_exists: Optional[bool] = None, + ignore_read_only: Optional[bool] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + metadata: Optional[Dict[str, str]] = None, + source_lease_access_conditions: Optional[_models.SourceLeaseAccessConditions] = None, + destination_lease_access_conditions: Optional[_models.DestinationLeaseAccessConditions] = None, + copy_file_smb_info: Optional[_models.CopyFileSmbInfo] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Renames a directory. + + :param rename_source: Required. Specifies the URI-style path of the source file, up to 2 KB in + length. Required. + :type rename_source: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param replace_if_exists: Optional. A boolean value for if the destination file already exists, + whether this request will overwrite the file or not. If true, the rename will succeed and will + overwrite the destination file. If not provided or if false and the destination file does + exist, the request will not overwrite the destination file. If provided and the destination + file doesn’t exist, the rename will succeed. Note: This value does not override the + x-ms-file-copy-ignore-read-only header value. Default value is None. + :type replace_if_exists: bool + :param ignore_read_only: Optional. A boolean value that specifies whether the ReadOnly + attribute on a preexisting destination file should be respected. If true, the rename will + succeed, otherwise, a previous file at the destination with the ReadOnly attribute set will + cause the rename to fail. Default value is None. + :type ignore_read_only: bool + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param source_lease_access_conditions: Parameter group. Default value is None. + :type source_lease_access_conditions: + ~azure.storage.fileshare.models.SourceLeaseAccessConditions + :param destination_lease_access_conditions: Parameter group. Default value is None. + :type destination_lease_access_conditions: + ~azure.storage.fileshare.models.DestinationLeaseAccessConditions + :param copy_file_smb_info: Parameter group. Default value is None. + :type copy_file_smb_info: ~azure.storage.fileshare.models.CopyFileSmbInfo + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + comp: Literal["rename"] = kwargs.pop("comp", _params.pop("comp", "rename")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _source_lease_id = None + _destination_lease_id = None + _file_attributes = None + _file_creation_time = None + _file_last_write_time = None + _file_change_time = None + if source_lease_access_conditions is not None: + _source_lease_id = source_lease_access_conditions.source_lease_id + if destination_lease_access_conditions is not None: + _destination_lease_id = destination_lease_access_conditions.destination_lease_id + if copy_file_smb_info is not None: + _file_attributes = copy_file_smb_info.file_attributes + _file_change_time = copy_file_smb_info.file_change_time + _file_creation_time = copy_file_smb_info.file_creation_time + _file_last_write_time = copy_file_smb_info.file_last_write_time + + _request = build_rename_request( + url=self._config.url, + rename_source=rename_source, + timeout=timeout, + replace_if_exists=replace_if_exists, + ignore_read_only=ignore_read_only, + source_lease_id=_source_lease_id, + destination_lease_id=_destination_lease_id, + file_attributes=_file_attributes, + file_creation_time=_file_creation_time, + file_last_write_time=_file_last_write_time, + file_change_time=_file_change_time, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + metadata=metadata, + allow_trailing_dot=self._config.allow_trailing_dot, + allow_source_trailing_dot=self._config.allow_source_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_file_operations.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_file_operations.py new file mode 100644 index 00000000..93f91f24 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_file_operations.py @@ -0,0 +1,2518 @@ +# pylint: disable=too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +import sys +from typing import Any, AsyncIterator, Callable, Dict, IO, Literal, Optional, TypeVar, Union + +from azure.core import AsyncPipelineClient +from azure.core.exceptions import ( + ClientAuthenticationError, + HttpResponseError, + ResourceExistsError, + ResourceNotFoundError, + ResourceNotModifiedError, + StreamClosedError, + StreamConsumedError, + map_error, +) +from azure.core.pipeline import PipelineResponse +from azure.core.rest import AsyncHttpResponse, HttpRequest +from azure.core.tracing.decorator_async import distributed_trace_async +from azure.core.utils import case_insensitive_dict + +from ... import models as _models +from ..._serialization import Deserializer, Serializer +from ...operations._file_operations import ( + build_abort_copy_request, + build_acquire_lease_request, + build_break_lease_request, + build_change_lease_request, + build_create_hard_link_request, + build_create_request, + build_create_symbolic_link_request, + build_delete_request, + build_download_request, + build_force_close_handles_request, + build_get_properties_request, + build_get_range_list_request, + build_get_symbolic_link_request, + build_list_handles_request, + build_release_lease_request, + build_rename_request, + build_set_http_headers_request, + build_set_metadata_request, + build_start_copy_request, + build_upload_range_from_url_request, + build_upload_range_request, +) +from .._configuration import AzureFileStorageConfiguration + +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore +T = TypeVar("T") +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + + +class FileOperations: # pylint: disable=too-many-public-methods + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.storage.fileshare.aio.AzureFileStorage`'s + :attr:`file` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AzureFileStorageConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace_async + async def create( + self, + file_content_length: int, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + file_attributes: str = "none", + file_creation_time: str = "now", + file_last_write_time: str = "now", + file_change_time: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + nfs_file_type: Optional[Union[str, _models.NfsFileType]] = None, + file_http_headers: Optional[_models.FileHTTPHeaders] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Creates a new file or replaces a file. Note it only initializes the file with no content. + + :param file_content_length: Specifies the maximum size for the file, up to 4 TB. Required. + :type file_content_length: int + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param file_attributes: If specified, the provided file attributes shall be set. Default value: + ‘Archive’ for file and ‘Directory’ for directory. ‘None’ can also be specified as default. + Default value is "none". + :type file_attributes: str + :param file_creation_time: Creation time for the file/directory. Default value: Now. Default + value is "now". + :type file_creation_time: str + :param file_last_write_time: Last write time for the file/directory. Default value: Now. + Default value is "now". + :type file_last_write_time: str + :param file_change_time: Change time for the file/directory. Default value: Now. Default value + is None. + :type file_change_time: str + :param owner: Optional, NFS only. The owner of the file or directory. Default value is None. + :type owner: str + :param group: Optional, NFS only. The owning group of the file or directory. Default value is + None. + :type group: str + :param file_mode: Optional, NFS only. The file mode of the file or directory. Default value is + None. + :type file_mode: str + :param nfs_file_type: Optional, NFS only. Type of the file or directory. Known values are: + "Regular", "Directory", and "SymLink". Default value is None. + :type nfs_file_type: str or ~azure.storage.fileshare.models.NfsFileType + :param file_http_headers: Parameter group. Default value is None. + :type file_http_headers: ~azure.storage.fileshare.models.FileHTTPHeaders + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + file_type_constant: Literal["file"] = kwargs.pop("file_type_constant", _headers.pop("x-ms-type", "file")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _file_content_type = None + _file_content_encoding = None + _file_content_language = None + _file_cache_control = None + _file_content_md5 = None + _file_content_disposition = None + _lease_id = None + if file_http_headers is not None: + _file_cache_control = file_http_headers.file_cache_control + _file_content_disposition = file_http_headers.file_content_disposition + _file_content_encoding = file_http_headers.file_content_encoding + _file_content_language = file_http_headers.file_content_language + _file_content_md5 = file_http_headers.file_content_md5 + _file_content_type = file_http_headers.file_content_type + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_create_request( + url=self._config.url, + file_content_length=file_content_length, + timeout=timeout, + file_content_type=_file_content_type, + file_content_encoding=_file_content_encoding, + file_content_language=_file_content_language, + file_cache_control=_file_cache_control, + file_content_md5=_file_content_md5, + file_content_disposition=_file_content_disposition, + metadata=metadata, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + file_attributes=file_attributes, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + file_change_time=file_change_time, + lease_id=_lease_id, + owner=owner, + group=group, + file_mode=file_mode, + nfs_file_type=nfs_file_type, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + file_type_constant=file_type_constant, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-file-file-type"] = self._deserialize("str", response.headers.get("x-ms-file-file-type")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def download( + self, + timeout: Optional[int] = None, + range: Optional[str] = None, + range_get_content_md5: Optional[bool] = None, + structured_body_type: Optional[str] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> AsyncIterator[bytes]: + # pylint: disable=line-too-long + """Reads or downloads a file from the system, including its metadata and properties. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param range: Return file data only from the specified byte range. Default value is None. + :type range: str + :param range_get_content_md5: When this header is set to true and specified together with the + Range header, the service returns the MD5 hash for the range, as long as the range is less than + or equal to 4 MB in size. Default value is None. + :type range_get_content_md5: bool + :param structured_body_type: Specifies the response content should be returned as a structured + message and specifies the message schema version and properties. Default value is None. + :type structured_body_type: str + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: AsyncIterator[bytes] or the result of cls(response) + :rtype: AsyncIterator[bytes] + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[AsyncIterator[bytes]] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_download_request( + url=self._config.url, + timeout=timeout, + range=range, + range_get_content_md5=range_get_content_md5, + structured_body_type=structured_body_type, + lease_id=_lease_id, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _decompress = kwargs.pop("decompress", True) + _stream = True + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200, 206]: + try: + await response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-meta"] = self._deserialize("{str}", response.headers.get("x-ms-meta")) + response_headers["Content-Length"] = self._deserialize("int", response.headers.get("Content-Length")) + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + response_headers["Content-Range"] = self._deserialize("str", response.headers.get("Content-Range")) + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Content-MD5"] = self._deserialize("bytearray", response.headers.get("Content-MD5")) + response_headers["Content-Encoding"] = self._deserialize("str", response.headers.get("Content-Encoding")) + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Content-Disposition"] = self._deserialize("str", response.headers.get("Content-Disposition")) + response_headers["Content-Language"] = self._deserialize("str", response.headers.get("Content-Language")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Accept-Ranges"] = self._deserialize("str", response.headers.get("Accept-Ranges")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-copy-completion-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-copy-completion-time") + ) + response_headers["x-ms-copy-status-description"] = self._deserialize( + "str", response.headers.get("x-ms-copy-status-description") + ) + response_headers["x-ms-copy-id"] = self._deserialize("str", response.headers.get("x-ms-copy-id")) + response_headers["x-ms-copy-progress"] = self._deserialize("str", response.headers.get("x-ms-copy-progress")) + response_headers["x-ms-copy-source"] = self._deserialize("str", response.headers.get("x-ms-copy-source")) + response_headers["x-ms-copy-status"] = self._deserialize("str", response.headers.get("x-ms-copy-status")) + response_headers["x-ms-content-md5"] = self._deserialize("bytearray", response.headers.get("x-ms-content-md5")) + response_headers["x-ms-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-server-encrypted") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-lease-duration"] = self._deserialize("str", response.headers.get("x-ms-lease-duration")) + response_headers["x-ms-lease-state"] = self._deserialize("str", response.headers.get("x-ms-lease-state")) + response_headers["x-ms-lease-status"] = self._deserialize("str", response.headers.get("x-ms-lease-status")) + response_headers["x-ms-structured-body"] = self._deserialize( + "str", response.headers.get("x-ms-structured-body") + ) + response_headers["x-ms-structured-content-length"] = self._deserialize( + "int", response.headers.get("x-ms-structured-content-length") + ) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-link-count"] = self._deserialize("int", response.headers.get("x-ms-link-count")) + + deserialized = response.stream_download(self._client._pipeline, decompress=_decompress) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def get_properties( + self, + sharesnapshot: Optional[str] = None, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Returns all user-defined metadata, standard HTTP properties, and system properties for the + file. It does not return the content of the file. + + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_get_properties_request( + url=self._config.url, + sharesnapshot=sharesnapshot, + timeout=timeout, + lease_id=_lease_id, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-meta"] = self._deserialize("{str}", response.headers.get("x-ms-meta")) + response_headers["x-ms-type"] = self._deserialize("str", response.headers.get("x-ms-type")) + response_headers["Content-Length"] = self._deserialize("int", response.headers.get("Content-Length")) + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Content-MD5"] = self._deserialize("bytearray", response.headers.get("Content-MD5")) + response_headers["Content-Encoding"] = self._deserialize("str", response.headers.get("Content-Encoding")) + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Content-Disposition"] = self._deserialize("str", response.headers.get("Content-Disposition")) + response_headers["Content-Language"] = self._deserialize("str", response.headers.get("Content-Language")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-copy-completion-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-copy-completion-time") + ) + response_headers["x-ms-copy-status-description"] = self._deserialize( + "str", response.headers.get("x-ms-copy-status-description") + ) + response_headers["x-ms-copy-id"] = self._deserialize("str", response.headers.get("x-ms-copy-id")) + response_headers["x-ms-copy-progress"] = self._deserialize("str", response.headers.get("x-ms-copy-progress")) + response_headers["x-ms-copy-source"] = self._deserialize("str", response.headers.get("x-ms-copy-source")) + response_headers["x-ms-copy-status"] = self._deserialize("str", response.headers.get("x-ms-copy-status")) + response_headers["x-ms-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-server-encrypted") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-lease-duration"] = self._deserialize("str", response.headers.get("x-ms-lease-duration")) + response_headers["x-ms-lease-state"] = self._deserialize("str", response.headers.get("x-ms-lease-state")) + response_headers["x-ms-lease-status"] = self._deserialize("str", response.headers.get("x-ms-lease-status")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-link-count"] = self._deserialize("int", response.headers.get("x-ms-link-count")) + response_headers["x-ms-file-file-type"] = self._deserialize("str", response.headers.get("x-ms-file-file-type")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def delete( + self, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """removes the file from the storage account. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_delete_request( + url=self._config.url, + timeout=timeout, + lease_id=_lease_id, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-link-count"] = self._deserialize("int", response.headers.get("x-ms-link-count")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def set_http_headers( + self, + timeout: Optional[int] = None, + file_content_length: Optional[int] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + file_attributes: str = "none", + file_creation_time: str = "now", + file_last_write_time: str = "now", + file_change_time: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + file_http_headers: Optional[_models.FileHTTPHeaders] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Sets HTTP headers on the file. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param file_content_length: Resizes a file to the specified size. If the specified byte value + is less than the current size of the file, then all ranges above the specified byte value are + cleared. Default value is None. + :type file_content_length: int + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param file_attributes: If specified, the provided file attributes shall be set. Default value: + ‘Archive’ for file and ‘Directory’ for directory. ‘None’ can also be specified as default. + Default value is "none". + :type file_attributes: str + :param file_creation_time: Creation time for the file/directory. Default value: Now. Default + value is "now". + :type file_creation_time: str + :param file_last_write_time: Last write time for the file/directory. Default value: Now. + Default value is "now". + :type file_last_write_time: str + :param file_change_time: Change time for the file/directory. Default value: Now. Default value + is None. + :type file_change_time: str + :param owner: Optional, NFS only. The owner of the file or directory. Default value is None. + :type owner: str + :param group: Optional, NFS only. The owning group of the file or directory. Default value is + None. + :type group: str + :param file_mode: Optional, NFS only. The file mode of the file or directory. Default value is + None. + :type file_mode: str + :param file_http_headers: Parameter group. Default value is None. + :type file_http_headers: ~azure.storage.fileshare.models.FileHTTPHeaders + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _file_content_type = None + _file_content_encoding = None + _file_content_language = None + _file_cache_control = None + _file_content_md5 = None + _file_content_disposition = None + _lease_id = None + if file_http_headers is not None: + _file_cache_control = file_http_headers.file_cache_control + _file_content_disposition = file_http_headers.file_content_disposition + _file_content_encoding = file_http_headers.file_content_encoding + _file_content_language = file_http_headers.file_content_language + _file_content_md5 = file_http_headers.file_content_md5 + _file_content_type = file_http_headers.file_content_type + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_set_http_headers_request( + url=self._config.url, + timeout=timeout, + file_content_length=file_content_length, + file_content_type=_file_content_type, + file_content_encoding=_file_content_encoding, + file_content_language=_file_content_language, + file_cache_control=_file_cache_control, + file_content_md5=_file_content_md5, + file_content_disposition=_file_content_disposition, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + file_attributes=file_attributes, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + file_change_time=file_change_time, + lease_id=_lease_id, + owner=owner, + group=group, + file_mode=file_mode, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-link-count"] = self._deserialize("int", response.headers.get("x-ms-link-count")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def set_metadata( + self, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Updates user-defined metadata for the specified file. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["metadata"] = kwargs.pop("comp", _params.pop("comp", "metadata")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_set_metadata_request( + url=self._config.url, + timeout=timeout, + metadata=metadata, + lease_id=_lease_id, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def acquire_lease( + self, + timeout: Optional[int] = None, + duration: Optional[int] = None, + proposed_lease_id: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """[Update] The Lease File operation establishes and manages a lock on a file for write and delete + operations. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param duration: Specifies the duration of the lease, in seconds, or negative one (-1) for a + lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease + duration cannot be changed using renew or change. Default value is None. + :type duration: int + :param proposed_lease_id: Proposed lease ID, in a GUID string format. The File service returns + 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid + Constructor (String) for a list of valid GUID string formats. Default value is None. + :type proposed_lease_id: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["acquire"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "acquire")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_acquire_lease_request( + url=self._config.url, + timeout=timeout, + duration=duration, + proposed_lease_id=proposed_lease_id, + request_id_parameter=request_id_parameter, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def release_lease( + self, lease_id: str, timeout: Optional[int] = None, request_id_parameter: Optional[str] = None, **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """[Update] The Lease File operation establishes and manages a lock on a file for write and delete + operations. + + :param lease_id: Specifies the current lease ID on the resource. Required. + :type lease_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["release"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "release")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_release_lease_request( + url=self._config.url, + lease_id=lease_id, + timeout=timeout, + request_id_parameter=request_id_parameter, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def change_lease( + self, + lease_id: str, + timeout: Optional[int] = None, + proposed_lease_id: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """[Update] The Lease File operation establishes and manages a lock on a file for write and delete + operations. + + :param lease_id: Specifies the current lease ID on the resource. Required. + :type lease_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param proposed_lease_id: Proposed lease ID, in a GUID string format. The File service returns + 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid + Constructor (String) for a list of valid GUID string formats. Default value is None. + :type proposed_lease_id: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["change"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "change")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_change_lease_request( + url=self._config.url, + lease_id=lease_id, + timeout=timeout, + proposed_lease_id=proposed_lease_id, + request_id_parameter=request_id_parameter, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def break_lease( + self, + timeout: Optional[int] = None, + request_id_parameter: Optional[str] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """[Update] The Lease File operation establishes and manages a lock on a file for write and delete + operations. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["break"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "break")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_break_lease_request( + url=self._config.url, + timeout=timeout, + lease_id=_lease_id, + request_id_parameter=request_id_parameter, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def upload_range( + self, + range: str, + content_length: int, + timeout: Optional[int] = None, + file_range_write: Union[str, _models.FileRangeWriteType] = "update", + content_md5: Optional[bytes] = None, + file_last_written_mode: Optional[Union[str, _models.FileLastWrittenMode]] = None, + structured_body_type: Optional[str] = None, + structured_content_length: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + optionalbody: Optional[IO[bytes]] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Upload a range of bytes to a file. + + :param range: Specifies the range of bytes to be written. Both the start and end of the range + must be specified. For an update operation, the range can be up to 4 MB in size. For a clear + operation, the range can be up to the value of the file's full size. The File service accepts + only a single byte range for the Range and 'x-ms-range' headers, and the byte range must be + specified in the following format: bytes=startByte-endByte. Required. + :type range: str + :param content_length: Specifies the number of bytes being transmitted in the request body. + When the x-ms-write header is set to clear, the value of this header must be set to zero. + Required. + :type content_length: int + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param file_range_write: Specify one of the following options: - Update: Writes the bytes + specified by the request body into the specified range. The Range and Content-Length headers + must match to perform the update. - Clear: Clears the specified range and releases the space + used in storage for that range. To clear a range, set the Content-Length header to zero, and + set the Range header to a value that indicates the range to clear, up to maximum file size. + Known values are: "update" and "clear". Default value is "update". + :type file_range_write: str or ~azure.storage.fileshare.models.FileRangeWriteType + :param content_md5: An MD5 hash of the content. This hash is used to verify the integrity of + the data during transport. When the Content-MD5 header is specified, the File service compares + the hash of the content that has arrived with the header value that was sent. If the two hashes + do not match, the operation will fail with error code 400 (Bad Request). Default value is None. + :type content_md5: bytes + :param file_last_written_mode: If the file last write time should be preserved or overwritten. + Known values are: "Now" and "Preserve". Default value is None. + :type file_last_written_mode: str or ~azure.storage.fileshare.models.FileLastWrittenMode + :param structured_body_type: Required if the request body is a structured message. Specifies + the message schema version and properties. Default value is None. + :type structured_body_type: str + :param structured_content_length: Required if the request body is a structured message. + Specifies the length of the blob/file content inside the message body. Will always be smaller + than Content-Length. Default value is None. + :type structured_content_length: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :param optionalbody: Initial data. Default value is None. + :type optionalbody: IO[bytes] + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["range"] = kwargs.pop("comp", _params.pop("comp", "range")) + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/octet-stream")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + _content = optionalbody + + _request = build_upload_range_request( + url=self._config.url, + range=range, + content_length=content_length, + timeout=timeout, + file_range_write=file_range_write, + content_md5=content_md5, + lease_id=_lease_id, + file_last_written_mode=file_last_written_mode, + structured_body_type=structured_body_type, + structured_content_length=structured_content_length, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + content_type=content_type, + version=self._config.version, + content=_content, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["Content-MD5"] = self._deserialize("bytearray", response.headers.get("Content-MD5")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-structured-body"] = self._deserialize( + "str", response.headers.get("x-ms-structured-body") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def upload_range_from_url( + self, + range: str, + copy_source: str, + content_length: int, + timeout: Optional[int] = None, + source_range: Optional[str] = None, + source_content_crc64: Optional[bytes] = None, + copy_source_authorization: Optional[str] = None, + file_last_written_mode: Optional[Union[str, _models.FileLastWrittenMode]] = None, + source_modified_access_conditions: Optional[_models.SourceModifiedAccessConditions] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Upload a range of bytes to a file where the contents are read from a URL. + + :param range: Writes data to the specified byte range in the file. Required. + :type range: str + :param copy_source: Specifies the URL of the source file or blob, up to 2 KB in length. To copy + a file to another file within the same storage account, you may use Shared Key to authenticate + the source file. If you are copying a file from another storage account, or if you are copying + a blob from the same storage account or another storage account, then you must authenticate the + source file or blob using a shared access signature. If the source is a public blob, no + authentication is required to perform the copy operation. A file in a share snapshot can also + be specified as a copy source. Required. + :type copy_source: str + :param content_length: Specifies the number of bytes being transmitted in the request body. + When the x-ms-write header is set to clear, the value of this header must be set to zero. + Required. + :type content_length: int + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param source_range: Bytes of source data in the specified range. Default value is None. + :type source_range: str + :param source_content_crc64: Specify the crc64 calculated for the range of bytes that must be + read from the copy source. Default value is None. + :type source_content_crc64: bytes + :param copy_source_authorization: Only Bearer type is supported. Credentials should be a valid + OAuth access token to copy source. Default value is None. + :type copy_source_authorization: str + :param file_last_written_mode: If the file last write time should be preserved or overwritten. + Known values are: "Now" and "Preserve". Default value is None. + :type file_last_written_mode: str or ~azure.storage.fileshare.models.FileLastWrittenMode + :param source_modified_access_conditions: Parameter group. Default value is None. + :type source_modified_access_conditions: + ~azure.storage.fileshare.models.SourceModifiedAccessConditions + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["range"] = kwargs.pop("comp", _params.pop("comp", "range")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _source_if_match_crc64 = None + _source_if_none_match_crc64 = None + _lease_id = None + if source_modified_access_conditions is not None: + _source_if_match_crc64 = source_modified_access_conditions.source_if_match_crc64 + _source_if_none_match_crc64 = source_modified_access_conditions.source_if_none_match_crc64 + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_upload_range_from_url_request( + url=self._config.url, + range=range, + copy_source=copy_source, + content_length=content_length, + timeout=timeout, + source_range=source_range, + source_content_crc64=source_content_crc64, + source_if_match_crc64=_source_if_match_crc64, + source_if_none_match_crc64=_source_if_none_match_crc64, + lease_id=_lease_id, + copy_source_authorization=copy_source_authorization, + file_last_written_mode=file_last_written_mode, + allow_trailing_dot=self._config.allow_trailing_dot, + allow_source_trailing_dot=self._config.allow_source_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + file_range_write_from_url=self._config.file_range_write_from_url, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-content-crc64"] = self._deserialize( + "bytearray", response.headers.get("x-ms-content-crc64") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def get_range_list( + self, + sharesnapshot: Optional[str] = None, + prevsharesnapshot: Optional[str] = None, + timeout: Optional[int] = None, + range: Optional[str] = None, + support_rename: Optional[bool] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> _models.ShareFileRangeList: + # pylint: disable=line-too-long + """Returns the list of valid ranges for a file. + + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param prevsharesnapshot: The previous snapshot parameter is an opaque DateTime value that, + when present, specifies the previous snapshot. Default value is None. + :type prevsharesnapshot: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param range: Specifies the range of bytes over which to list ranges, inclusively. Default + value is None. + :type range: str + :param support_rename: This header is allowed only when PrevShareSnapshot query parameter is + set. Determines whether the changed ranges for a file that has been renamed or moved between + the target snapshot (or the live file) and the previous snapshot should be listed. If the value + is true, the valid changed ranges for the file will be returned. If the value is false, the + operation will result in a failure with 409 (Conflict) response. The default value is false. + Default value is None. + :type support_rename: bool + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: ShareFileRangeList or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.ShareFileRangeList + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["rangelist"] = kwargs.pop("comp", _params.pop("comp", "rangelist")) + cls: ClsType[_models.ShareFileRangeList] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_get_range_list_request( + url=self._config.url, + sharesnapshot=sharesnapshot, + prevsharesnapshot=prevsharesnapshot, + timeout=timeout, + range=range, + lease_id=_lease_id, + support_rename=support_rename, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["x-ms-content-length"] = self._deserialize("int", response.headers.get("x-ms-content-length")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("ShareFileRangeList", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def start_copy( + self, + copy_source: str, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + file_mode_copy_mode: Optional[Union[str, _models.ModeCopyMode]] = None, + file_owner_copy_mode: Optional[Union[str, _models.OwnerCopyMode]] = None, + copy_file_smb_info: Optional[_models.CopyFileSmbInfo] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Copies a blob or file to a destination file within the storage account. + + :param copy_source: Specifies the URL of the source file or blob, up to 2 KB in length. To copy + a file to another file within the same storage account, you may use Shared Key to authenticate + the source file. If you are copying a file from another storage account, or if you are copying + a blob from the same storage account or another storage account, then you must authenticate the + source file or blob using a shared access signature. If the source is a public blob, no + authentication is required to perform the copy operation. A file in a share snapshot can also + be specified as a copy source. Required. + :type copy_source: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param owner: Optional, NFS only. The owner of the file or directory. Default value is None. + :type owner: str + :param group: Optional, NFS only. The owning group of the file or directory. Default value is + None. + :type group: str + :param file_mode: Optional, NFS only. The file mode of the file or directory. Default value is + None. + :type file_mode: str + :param file_mode_copy_mode: NFS only. Applicable only when the copy source is a File. + Determines the copy behavior of the mode bits of the file. source: The mode on the destination + file is copied from the source file. override: The mode on the destination file is determined + via the x-ms-mode header. Known values are: "source" and "override". Default value is None. + :type file_mode_copy_mode: str or ~azure.storage.fileshare.models.ModeCopyMode + :param file_owner_copy_mode: NFS only. Determines the copy behavior of the owner user + identifier (UID) and group identifier (GID) of the file. source: The owner user identifier + (UID) and group identifier (GID) on the destination file is copied from the source file. + override: The owner user identifier (UID) and group identifier (GID) on the destination file is + determined via the x-ms-owner and x-ms-group headers. Known values are: "source" and + "override". Default value is None. + :type file_owner_copy_mode: str or ~azure.storage.fileshare.models.OwnerCopyMode + :param copy_file_smb_info: Parameter group. Default value is None. + :type copy_file_smb_info: ~azure.storage.fileshare.models.CopyFileSmbInfo + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _file_permission_copy_mode = None + _ignore_read_only = None + _file_attributes = None + _file_creation_time = None + _file_last_write_time = None + _file_change_time = None + _set_archive_attribute = None + _lease_id = None + if copy_file_smb_info is not None: + _file_attributes = copy_file_smb_info.file_attributes + _file_change_time = copy_file_smb_info.file_change_time + _file_creation_time = copy_file_smb_info.file_creation_time + _file_last_write_time = copy_file_smb_info.file_last_write_time + _file_permission_copy_mode = copy_file_smb_info.file_permission_copy_mode + _ignore_read_only = copy_file_smb_info.ignore_read_only + _set_archive_attribute = copy_file_smb_info.set_archive_attribute + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_start_copy_request( + url=self._config.url, + copy_source=copy_source, + timeout=timeout, + metadata=metadata, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + file_permission_copy_mode=_file_permission_copy_mode, + ignore_read_only=_ignore_read_only, + file_attributes=_file_attributes, + file_creation_time=_file_creation_time, + file_last_write_time=_file_last_write_time, + file_change_time=_file_change_time, + set_archive_attribute=_set_archive_attribute, + lease_id=_lease_id, + owner=owner, + group=group, + file_mode=file_mode, + file_mode_copy_mode=file_mode_copy_mode, + file_owner_copy_mode=file_owner_copy_mode, + allow_trailing_dot=self._config.allow_trailing_dot, + allow_source_trailing_dot=self._config.allow_source_trailing_dot, + file_request_intent=self._config.file_request_intent, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-copy-id"] = self._deserialize("str", response.headers.get("x-ms-copy-id")) + response_headers["x-ms-copy-status"] = self._deserialize("str", response.headers.get("x-ms-copy-status")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def abort_copy( + self, + copy_id: str, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Aborts a pending Copy File operation, and leaves a destination file with zero length and full + metadata. + + :param copy_id: The copy identifier provided in the x-ms-copy-id header of the original Copy + File operation. Required. + :type copy_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["copy"] = kwargs.pop("comp", _params.pop("comp", "copy")) + copy_action_abort_constant: Literal["abort"] = kwargs.pop( + "copy_action_abort_constant", _headers.pop("x-ms-copy-action", "abort") + ) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_abort_copy_request( + url=self._config.url, + copy_id=copy_id, + timeout=timeout, + lease_id=_lease_id, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + copy_action_abort_constant=copy_action_abort_constant, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def list_handles( + self, + marker: Optional[str] = None, + maxresults: Optional[int] = None, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + **kwargs: Any + ) -> _models.ListHandlesResponse: + # pylint: disable=line-too-long + """Lists handles for file. + + :param marker: A string value that identifies the portion of the list to be returned with the + next list operation. The operation returns a marker value within the response body if the list + returned was not complete. The marker value may then be used in a subsequent call to request + the next set of list items. The marker value is opaque to the client. Default value is None. + :type marker: str + :param maxresults: Specifies the maximum number of entries to return. If the request does not + specify maxresults, or specifies a value greater than 5,000, the server will return up to 5,000 + items. Default value is None. + :type maxresults: int + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :return: ListHandlesResponse or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.ListHandlesResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["listhandles"] = kwargs.pop("comp", _params.pop("comp", "listhandles")) + cls: ClsType[_models.ListHandlesResponse] = kwargs.pop("cls", None) + + _request = build_list_handles_request( + url=self._config.url, + marker=marker, + maxresults=maxresults, + timeout=timeout, + sharesnapshot=sharesnapshot, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("ListHandlesResponse", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def force_close_handles( + self, + handle_id: str, + timeout: Optional[int] = None, + marker: Optional[str] = None, + sharesnapshot: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Closes all handles open for given file. + + :param handle_id: Specifies handle ID opened on the file or directory to be closed. Asterisk + (‘*’) is a wildcard that specifies all handles. Required. + :type handle_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param marker: A string value that identifies the portion of the list to be returned with the + next list operation. The operation returns a marker value within the response body if the list + returned was not complete. The marker value may then be used in a subsequent call to request + the next set of list items. The marker value is opaque to the client. Default value is None. + :type marker: str + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["forceclosehandles"] = kwargs.pop("comp", _params.pop("comp", "forceclosehandles")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_force_close_handles_request( + url=self._config.url, + handle_id=handle_id, + timeout=timeout, + marker=marker, + sharesnapshot=sharesnapshot, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-marker"] = self._deserialize("str", response.headers.get("x-ms-marker")) + response_headers["x-ms-number-of-handles-closed"] = self._deserialize( + "int", response.headers.get("x-ms-number-of-handles-closed") + ) + response_headers["x-ms-number-of-handles-failed"] = self._deserialize( + "int", response.headers.get("x-ms-number-of-handles-failed") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def rename( + self, + rename_source: str, + timeout: Optional[int] = None, + replace_if_exists: Optional[bool] = None, + ignore_read_only: Optional[bool] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + metadata: Optional[Dict[str, str]] = None, + source_lease_access_conditions: Optional[_models.SourceLeaseAccessConditions] = None, + destination_lease_access_conditions: Optional[_models.DestinationLeaseAccessConditions] = None, + copy_file_smb_info: Optional[_models.CopyFileSmbInfo] = None, + file_http_headers: Optional[_models.FileHTTPHeaders] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Renames a file. + + :param rename_source: Required. Specifies the URI-style path of the source file, up to 2 KB in + length. Required. + :type rename_source: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param replace_if_exists: Optional. A boolean value for if the destination file already exists, + whether this request will overwrite the file or not. If true, the rename will succeed and will + overwrite the destination file. If not provided or if false and the destination file does + exist, the request will not overwrite the destination file. If provided and the destination + file doesn’t exist, the rename will succeed. Note: This value does not override the + x-ms-file-copy-ignore-read-only header value. Default value is None. + :type replace_if_exists: bool + :param ignore_read_only: Optional. A boolean value that specifies whether the ReadOnly + attribute on a preexisting destination file should be respected. If true, the rename will + succeed, otherwise, a previous file at the destination with the ReadOnly attribute set will + cause the rename to fail. Default value is None. + :type ignore_read_only: bool + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param source_lease_access_conditions: Parameter group. Default value is None. + :type source_lease_access_conditions: + ~azure.storage.fileshare.models.SourceLeaseAccessConditions + :param destination_lease_access_conditions: Parameter group. Default value is None. + :type destination_lease_access_conditions: + ~azure.storage.fileshare.models.DestinationLeaseAccessConditions + :param copy_file_smb_info: Parameter group. Default value is None. + :type copy_file_smb_info: ~azure.storage.fileshare.models.CopyFileSmbInfo + :param file_http_headers: Parameter group. Default value is None. + :type file_http_headers: ~azure.storage.fileshare.models.FileHTTPHeaders + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["rename"] = kwargs.pop("comp", _params.pop("comp", "rename")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _source_lease_id = None + _destination_lease_id = None + _file_attributes = None + _file_creation_time = None + _file_last_write_time = None + _file_change_time = None + _file_content_type = None + if source_lease_access_conditions is not None: + _source_lease_id = source_lease_access_conditions.source_lease_id + if destination_lease_access_conditions is not None: + _destination_lease_id = destination_lease_access_conditions.destination_lease_id + if copy_file_smb_info is not None: + _file_attributes = copy_file_smb_info.file_attributes + _file_change_time = copy_file_smb_info.file_change_time + _file_creation_time = copy_file_smb_info.file_creation_time + _file_last_write_time = copy_file_smb_info.file_last_write_time + if file_http_headers is not None: + _file_content_type = file_http_headers.file_content_type + + _request = build_rename_request( + url=self._config.url, + rename_source=rename_source, + timeout=timeout, + replace_if_exists=replace_if_exists, + ignore_read_only=ignore_read_only, + source_lease_id=_source_lease_id, + destination_lease_id=_destination_lease_id, + file_attributes=_file_attributes, + file_creation_time=_file_creation_time, + file_last_write_time=_file_last_write_time, + file_change_time=_file_change_time, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + metadata=metadata, + file_content_type=_file_content_type, + allow_trailing_dot=self._config.allow_trailing_dot, + allow_source_trailing_dot=self._config.allow_source_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def create_symbolic_link( + self, + link_text: str, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + file_creation_time: str = "now", + file_last_write_time: str = "now", + request_id_parameter: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Creates a symbolic link. + + :param link_text: NFS only. Required. The path to the original file, the symbolic link is + pointing to. The path is of type string which is not resolved and is stored as is. The path can + be absolute path or the relative path depending on the content stored in the symbolic link + file. Required. + :type link_text: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param file_creation_time: Creation time for the file/directory. Default value: Now. Default + value is "now". + :type file_creation_time: str + :param file_last_write_time: Last write time for the file/directory. Default value: Now. + Default value is "now". + :type file_last_write_time: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :param owner: Optional, NFS only. The owner of the file or directory. Default value is None. + :type owner: str + :param group: Optional, NFS only. The owning group of the file or directory. Default value is + None. + :type group: str + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["symboliclink"] = kwargs.pop("restype", _params.pop("restype", "symboliclink")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_create_symbolic_link_request( + url=self._config.url, + link_text=link_text, + timeout=timeout, + metadata=metadata, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + request_id_parameter=request_id_parameter, + lease_id=_lease_id, + owner=owner, + group=group, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-file-file-type"] = self._deserialize("str", response.headers.get("x-ms-file-file-type")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def get_symbolic_link( + self, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """get_symbolic_link. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["symboliclink"] = kwargs.pop("restype", _params.pop("restype", "symboliclink")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_get_symbolic_link_request( + url=self._config.url, + timeout=timeout, + sharesnapshot=sharesnapshot, + request_id_parameter=request_id_parameter, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-link-text"] = self._deserialize("str", response.headers.get("x-ms-link-text")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def create_hard_link( + self, + target_file: str, + timeout: Optional[int] = None, + request_id_parameter: Optional[str] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Creates a hard link. + + :param target_file: NFS only. Required. Specifies the path of the target file to which the link + will be created, up to 2 KiB in length. It should be full path of the target from the root.The + target file must be in the same share and hence the same storage account. Required. + :type target_file: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["hardlink"] = kwargs.pop("restype", _params.pop("restype", "hardlink")) + file_type_constant: Literal["file"] = kwargs.pop("file_type_constant", _headers.pop("x-ms-type", "file")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_create_hard_link_request( + url=self._config.url, + target_file=target_file, + timeout=timeout, + request_id_parameter=request_id_parameter, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + file_type_constant=file_type_constant, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-link-count"] = self._deserialize("int", response.headers.get("x-ms-link-count")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-file-file-type"] = self._deserialize("str", response.headers.get("x-ms-file-file-type")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_patch.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_patch.py new file mode 100644 index 00000000..f7dd3251 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_patch.py @@ -0,0 +1,20 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Customize generated code here. + +Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize +""" +from typing import List + +__all__: List[str] = [] # Add all objects you want publicly available to users at this package level + + +def patch_sdk(): + """Do not remove from this file. + + `patch_sdk` is a last resort escape hatch that allows you to do customizations + you can't accomplish using the techniques described in + https://aka.ms/azsdk/python/dpcodegen/python/customize + """ diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_service_operations.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_service_operations.py new file mode 100644 index 00000000..4814e221 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_service_operations.py @@ -0,0 +1,284 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +import sys +from typing import Any, Callable, Dict, List, Literal, Optional, TypeVar, Union + +from azure.core import AsyncPipelineClient +from azure.core.exceptions import ( + ClientAuthenticationError, + HttpResponseError, + ResourceExistsError, + ResourceNotFoundError, + ResourceNotModifiedError, + map_error, +) +from azure.core.pipeline import PipelineResponse +from azure.core.rest import AsyncHttpResponse, HttpRequest +from azure.core.tracing.decorator_async import distributed_trace_async +from azure.core.utils import case_insensitive_dict + +from ... import models as _models +from ..._serialization import Deserializer, Serializer +from ...operations._service_operations import ( + build_get_properties_request, + build_list_shares_segment_request, + build_set_properties_request, +) +from .._configuration import AzureFileStorageConfiguration + +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore +T = TypeVar("T") +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + + +class ServiceOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.storage.fileshare.aio.AzureFileStorage`'s + :attr:`service` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AzureFileStorageConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace_async + async def set_properties( + self, storage_service_properties: _models.StorageServiceProperties, timeout: Optional[int] = None, **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Sets properties for a storage account's File service endpoint, including properties for Storage + Analytics metrics and CORS (Cross-Origin Resource Sharing) rules. + + :param storage_service_properties: The StorageService properties. Required. + :type storage_service_properties: ~azure.storage.fileshare.models.StorageServiceProperties + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["service"] = kwargs.pop("restype", _params.pop("restype", "service")) + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/xml")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _content = self._serialize.body(storage_service_properties, "StorageServiceProperties", is_xml=True) + + _request = build_set_properties_request( + url=self._config.url, + timeout=timeout, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + content_type=content_type, + version=self._config.version, + content=_content, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def get_properties(self, timeout: Optional[int] = None, **kwargs: Any) -> _models.StorageServiceProperties: + # pylint: disable=line-too-long + """Gets the properties of a storage account's File service, including properties for Storage + Analytics metrics and CORS (Cross-Origin Resource Sharing) rules. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: StorageServiceProperties or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.StorageServiceProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["service"] = kwargs.pop("restype", _params.pop("restype", "service")) + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + cls: ClsType[_models.StorageServiceProperties] = kwargs.pop("cls", None) + + _request = build_get_properties_request( + url=self._config.url, + timeout=timeout, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + + deserialized = self._deserialize("StorageServiceProperties", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def list_shares_segment( + self, + prefix: Optional[str] = None, + marker: Optional[str] = None, + maxresults: Optional[int] = None, + include: Optional[List[Union[str, _models.ListSharesIncludeType]]] = None, + timeout: Optional[int] = None, + **kwargs: Any + ) -> _models.ListSharesResponse: + # pylint: disable=line-too-long + """The List Shares Segment operation returns a list of the shares and share snapshots under the + specified account. + + :param prefix: Filters the results to return only entries whose name begins with the specified + prefix. Default value is None. + :type prefix: str + :param marker: A string value that identifies the portion of the list to be returned with the + next list operation. The operation returns a marker value within the response body if the list + returned was not complete. The marker value may then be used in a subsequent call to request + the next set of list items. The marker value is opaque to the client. Default value is None. + :type marker: str + :param maxresults: Specifies the maximum number of entries to return. If the request does not + specify maxresults, or specifies a value greater than 5,000, the server will return up to 5,000 + items. Default value is None. + :type maxresults: int + :param include: Include this parameter to specify one or more datasets to include in the + response. Default value is None. + :type include: list[str or ~azure.storage.fileshare.models.ListSharesIncludeType] + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: ListSharesResponse or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.ListSharesResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["list"] = kwargs.pop("comp", _params.pop("comp", "list")) + cls: ClsType[_models.ListSharesResponse] = kwargs.pop("cls", None) + + _request = build_list_shares_segment_request( + url=self._config.url, + prefix=prefix, + marker=marker, + maxresults=maxresults, + include=include, + timeout=timeout, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + + deserialized = self._deserialize("ListSharesResponse", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_share_operations.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_share_operations.py new file mode 100644 index 00000000..373424ef --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/aio/operations/_share_operations.py @@ -0,0 +1,1765 @@ +# pylint: disable=too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from io import IOBase +import sys +from typing import Any, Callable, Dict, IO, List, Literal, Optional, TypeVar, Union, overload + +from azure.core import AsyncPipelineClient +from azure.core.exceptions import ( + ClientAuthenticationError, + HttpResponseError, + ResourceExistsError, + ResourceNotFoundError, + ResourceNotModifiedError, + map_error, +) +from azure.core.pipeline import PipelineResponse +from azure.core.rest import AsyncHttpResponse, HttpRequest +from azure.core.tracing.decorator_async import distributed_trace_async +from azure.core.utils import case_insensitive_dict + +from ... import models as _models +from ..._serialization import Deserializer, Serializer +from ...operations._share_operations import ( + build_acquire_lease_request, + build_break_lease_request, + build_change_lease_request, + build_create_permission_request, + build_create_request, + build_create_snapshot_request, + build_delete_request, + build_get_access_policy_request, + build_get_permission_request, + build_get_properties_request, + build_get_statistics_request, + build_release_lease_request, + build_renew_lease_request, + build_restore_request, + build_set_access_policy_request, + build_set_metadata_request, + build_set_properties_request, +) +from .._configuration import AzureFileStorageConfiguration + +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore +T = TypeVar("T") +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, AsyncHttpResponse], T, Dict[str, Any]], Any]] + + +class ShareOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.storage.fileshare.aio.AzureFileStorage`'s + :attr:`share` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs) -> None: + input_args = list(args) + self._client: AsyncPipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AzureFileStorageConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace_async + async def create( + self, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + quota: Optional[int] = None, + access_tier: Optional[Union[str, _models.ShareAccessTier]] = None, + enabled_protocols: Optional[str] = None, + root_squash: Optional[Union[str, _models.ShareRootSquash]] = None, + enable_snapshot_virtual_directory_access: Optional[bool] = None, + paid_bursting_enabled: Optional[bool] = None, + paid_bursting_max_bandwidth_mibps: Optional[int] = None, + paid_bursting_max_iops: Optional[int] = None, + share_provisioned_iops: Optional[int] = None, + share_provisioned_bandwidth_mibps: Optional[int] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Creates a new share under the specified account. If the share with the same name already + exists, the operation fails. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param quota: Specifies the maximum size of the share, in gigabytes. Default value is None. + :type quota: int + :param access_tier: Specifies the access tier of the share. Known values are: + "TransactionOptimized", "Hot", "Cool", and "Premium". Default value is None. + :type access_tier: str or ~azure.storage.fileshare.models.ShareAccessTier + :param enabled_protocols: Protocols to enable on the share. Default value is None. + :type enabled_protocols: str + :param root_squash: Root squash to set on the share. Only valid for NFS shares. Known values + are: "NoRootSquash", "RootSquash", and "AllSquash". Default value is None. + :type root_squash: str or ~azure.storage.fileshare.models.ShareRootSquash + :param enable_snapshot_virtual_directory_access: Default value is None. + :type enable_snapshot_virtual_directory_access: bool + :param paid_bursting_enabled: Optional. Boolean. Default if not specified is false. This + property enables paid bursting. Default value is None. + :type paid_bursting_enabled: bool + :param paid_bursting_max_bandwidth_mibps: Optional. Integer. Default if not specified is the + maximum throughput the file share can support. Current maximum for a file share is 10,340 + MiB/sec. Default value is None. + :type paid_bursting_max_bandwidth_mibps: int + :param paid_bursting_max_iops: Optional. Integer. Default if not specified is the maximum IOPS + the file share can support. Current maximum for a file share is 102,400 IOPS. Default value is + None. + :type paid_bursting_max_iops: int + :param share_provisioned_iops: Optional. Supported in version 2025-01-05 and later. Only + allowed for provisioned v2 file shares. Specifies the provisioned number of input/output + operations per second (IOPS) of the share. If this is not specified, the provisioned IOPS is + set to value calculated based on recommendation formula. Default value is None. + :type share_provisioned_iops: int + :param share_provisioned_bandwidth_mibps: Optional. Supported in version 2025-01-05 and later. + Only allowed for provisioned v2 file shares. Specifies the provisioned bandwidth of the share, + in mebibytes per second (MiBps). If this is not specified, the provisioned bandwidth is set to + value calculated based on recommendation formula. Default value is None. + :type share_provisioned_bandwidth_mibps: int + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_create_request( + url=self._config.url, + timeout=timeout, + metadata=metadata, + quota=quota, + access_tier=access_tier, + enabled_protocols=enabled_protocols, + root_squash=root_squash, + enable_snapshot_virtual_directory_access=enable_snapshot_virtual_directory_access, + paid_bursting_enabled=paid_bursting_enabled, + paid_bursting_max_bandwidth_mibps=paid_bursting_max_bandwidth_mibps, + paid_bursting_max_iops=paid_bursting_max_iops, + share_provisioned_iops=share_provisioned_iops, + share_provisioned_bandwidth_mibps=share_provisioned_bandwidth_mibps, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-share-quota"] = self._deserialize("int", response.headers.get("x-ms-share-quota")) + response_headers["x-ms-share-provisioned-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-iops") + ) + response_headers["x-ms-share-provisioned-bandwidth-mibps"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-bandwidth-mibps") + ) + response_headers["x-ms-share-included-burst-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-included-burst-iops") + ) + response_headers["x-ms-share-max-burst-credits-for-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-max-burst-credits-for-iops") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def get_properties( + self, + sharesnapshot: Optional[str] = None, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Returns all user-defined metadata and system properties for the specified share or share + snapshot. The data returned does not include the share's list of files. + + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_get_properties_request( + url=self._config.url, + sharesnapshot=sharesnapshot, + timeout=timeout, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-meta"] = self._deserialize("{str}", response.headers.get("x-ms-meta")) + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-share-quota"] = self._deserialize("int", response.headers.get("x-ms-share-quota")) + response_headers["x-ms-share-provisioned-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-iops") + ) + response_headers["x-ms-share-provisioned-ingress-mbps"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-ingress-mbps") + ) + response_headers["x-ms-share-provisioned-egress-mbps"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-egress-mbps") + ) + response_headers["x-ms-share-next-allowed-quota-downgrade-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-share-next-allowed-quota-downgrade-time") + ) + response_headers["x-ms-share-provisioned-bandwidth-mibps"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-bandwidth-mibps") + ) + response_headers["x-ms-lease-duration"] = self._deserialize("str", response.headers.get("x-ms-lease-duration")) + response_headers["x-ms-lease-state"] = self._deserialize("str", response.headers.get("x-ms-lease-state")) + response_headers["x-ms-lease-status"] = self._deserialize("str", response.headers.get("x-ms-lease-status")) + response_headers["x-ms-access-tier"] = self._deserialize("str", response.headers.get("x-ms-access-tier")) + response_headers["x-ms-access-tier-change-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-access-tier-change-time") + ) + response_headers["x-ms-access-tier-transition-state"] = self._deserialize( + "str", response.headers.get("x-ms-access-tier-transition-state") + ) + response_headers["x-ms-enabled-protocols"] = self._deserialize( + "str", response.headers.get("x-ms-enabled-protocols") + ) + response_headers["x-ms-root-squash"] = self._deserialize("str", response.headers.get("x-ms-root-squash")) + response_headers["x-ms-enable-snapshot-virtual-directory-access"] = self._deserialize( + "bool", response.headers.get("x-ms-enable-snapshot-virtual-directory-access") + ) + response_headers["x-ms-share-paid-bursting-enabled"] = self._deserialize( + "bool", response.headers.get("x-ms-share-paid-bursting-enabled") + ) + response_headers["x-ms-share-paid-bursting-max-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-paid-bursting-max-iops") + ) + response_headers["x-ms-share-paid-bursting-max-bandwidth-mibps"] = self._deserialize( + "int", response.headers.get("x-ms-share-paid-bursting-max-bandwidth-mibps") + ) + response_headers["x-ms-share-included-burst-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-included-burst-iops") + ) + response_headers["x-ms-share-max-burst-credits-for-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-max-burst-credits-for-iops") + ) + response_headers["x-ms-share-next-allowed-provisioned-iops-downgrade-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-share-next-allowed-provisioned-iops-downgrade-time") + ) + response_headers["x-ms-share-next-allowed-provisioned-bandwidth-downgrade-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-share-next-allowed-provisioned-bandwidth-downgrade-time") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def delete( + self, + sharesnapshot: Optional[str] = None, + timeout: Optional[int] = None, + delete_snapshots: Optional[Union[str, _models.DeleteSnapshotsOptionType]] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Operation marks the specified share or share snapshot for deletion. The share or share snapshot + and any files contained within it are later deleted during garbage collection. + + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param delete_snapshots: Specifies the option include to delete the base share and all of its + snapshots. Known values are: "include" and "include-leased". Default value is None. + :type delete_snapshots: str or ~azure.storage.fileshare.models.DeleteSnapshotsOptionType + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_delete_request( + url=self._config.url, + sharesnapshot=sharesnapshot, + timeout=timeout, + delete_snapshots=delete_snapshots, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-file-share-usage-bytes"] = self._deserialize( + "int", response.headers.get("x-ms-file-share-usage-bytes") + ) + response_headers["x-ms-file-share-snapshot-usage-bytes"] = self._deserialize( + "int", response.headers.get("x-ms-file-share-snapshot-usage-bytes") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def acquire_lease( + self, + timeout: Optional[int] = None, + duration: Optional[int] = None, + proposed_lease_id: Optional[str] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """The Lease Share operation establishes and manages a lock on a share, or the specified snapshot + for set and delete share operations. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param duration: Specifies the duration of the lease, in seconds, or negative one (-1) for a + lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease + duration cannot be changed using renew or change. Default value is None. + :type duration: int + :param proposed_lease_id: Proposed lease ID, in a GUID string format. The File service returns + 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid + Constructor (String) for a list of valid GUID string formats. Default value is None. + :type proposed_lease_id: str + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["acquire"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "acquire")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_acquire_lease_request( + url=self._config.url, + timeout=timeout, + duration=duration, + proposed_lease_id=proposed_lease_id, + sharesnapshot=sharesnapshot, + request_id_parameter=request_id_parameter, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def release_lease( + self, + lease_id: str, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """The Lease Share operation establishes and manages a lock on a share, or the specified snapshot + for set and delete share operations. + + :param lease_id: Specifies the current lease ID on the resource. Required. + :type lease_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["release"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "release")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_release_lease_request( + url=self._config.url, + lease_id=lease_id, + timeout=timeout, + sharesnapshot=sharesnapshot, + request_id_parameter=request_id_parameter, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def change_lease( + self, + lease_id: str, + timeout: Optional[int] = None, + proposed_lease_id: Optional[str] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """The Lease Share operation establishes and manages a lock on a share, or the specified snapshot + for set and delete share operations. + + :param lease_id: Specifies the current lease ID on the resource. Required. + :type lease_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param proposed_lease_id: Proposed lease ID, in a GUID string format. The File service returns + 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid + Constructor (String) for a list of valid GUID string formats. Default value is None. + :type proposed_lease_id: str + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["change"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "change")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_change_lease_request( + url=self._config.url, + lease_id=lease_id, + timeout=timeout, + proposed_lease_id=proposed_lease_id, + sharesnapshot=sharesnapshot, + request_id_parameter=request_id_parameter, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def renew_lease( + self, + lease_id: str, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """The Lease Share operation establishes and manages a lock on a share, or the specified snapshot + for set and delete share operations. + + :param lease_id: Specifies the current lease ID on the resource. Required. + :type lease_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["renew"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "renew")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_renew_lease_request( + url=self._config.url, + lease_id=lease_id, + timeout=timeout, + sharesnapshot=sharesnapshot, + request_id_parameter=request_id_parameter, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def break_lease( + self, + timeout: Optional[int] = None, + break_period: Optional[int] = None, + request_id_parameter: Optional[str] = None, + sharesnapshot: Optional[str] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """The Lease Share operation establishes and manages a lock on a share, or the specified snapshot + for set and delete share operations. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param break_period: For a break operation, proposed duration the lease should continue before + it is broken, in seconds, between 0 and 60. This break period is only used if it is shorter + than the time remaining on the lease. If longer, the time remaining on the lease is used. A new + lease will not be available before the break period has expired, but the lease may be held for + longer than the break period. If this header does not appear with a break operation, a + fixed-duration lease breaks after the remaining lease period elapses, and an infinite lease + breaks immediately. Default value is None. + :type break_period: int + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["break"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "break")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_break_lease_request( + url=self._config.url, + timeout=timeout, + break_period=break_period, + lease_id=_lease_id, + request_id_parameter=request_id_parameter, + sharesnapshot=sharesnapshot, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-time"] = self._deserialize("int", response.headers.get("x-ms-lease-time")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def create_snapshot( + self, timeout: Optional[int] = None, metadata: Optional[Dict[str, str]] = None, **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Creates a read-only snapshot of a share. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["snapshot"] = kwargs.pop("comp", _params.pop("comp", "snapshot")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_create_snapshot_request( + url=self._config.url, + timeout=timeout, + metadata=metadata, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-snapshot"] = self._deserialize("str", response.headers.get("x-ms-snapshot")) + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @overload + async def create_permission( + self, + share_permission: _models.SharePermission, + timeout: Optional[int] = None, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Create a permission (a security descriptor). + + :param share_permission: A permission (a security descriptor) at the share level. Required. + :type share_permission: ~azure.storage.fileshare.models.SharePermission + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + async def create_permission( + self, + share_permission: IO[bytes], + timeout: Optional[int] = None, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Create a permission (a security descriptor). + + :param share_permission: A permission (a security descriptor) at the share level. Required. + :type share_permission: IO[bytes] + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace_async + async def create_permission( + self, share_permission: Union[_models.SharePermission, IO[bytes]], timeout: Optional[int] = None, **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Create a permission (a security descriptor). + + :param share_permission: A permission (a security descriptor) at the share level. Is either a + SharePermission type or a IO[bytes] type. Required. + :type share_permission: ~azure.storage.fileshare.models.SharePermission or IO[bytes] + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["filepermission"] = kwargs.pop("comp", _params.pop("comp", "filepermission")) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(share_permission, (IOBase, bytes)): + _content = share_permission + else: + _json = self._serialize.body(share_permission, "SharePermission") + + _request = build_create_permission_request( + url=self._config.url, + timeout=timeout, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + content_type=content_type, + version=self._config.version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def get_permission( + self, + file_permission_key: str, + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + timeout: Optional[int] = None, + **kwargs: Any + ) -> _models.SharePermission: + # pylint: disable=line-too-long + """Returns the permission (security descriptor) for a given key. + + :param file_permission_key: Key of the permission to be set for the directory/file. Required. + :type file_permission_key: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: SharePermission or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.SharePermission + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["filepermission"] = kwargs.pop("comp", _params.pop("comp", "filepermission")) + cls: ClsType[_models.SharePermission] = kwargs.pop("cls", None) + + _request = build_get_permission_request( + url=self._config.url, + file_permission_key=file_permission_key, + file_permission_format=file_permission_format, + timeout=timeout, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("SharePermission", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def set_properties( + self, + timeout: Optional[int] = None, + quota: Optional[int] = None, + access_tier: Optional[Union[str, _models.ShareAccessTier]] = None, + root_squash: Optional[Union[str, _models.ShareRootSquash]] = None, + enable_snapshot_virtual_directory_access: Optional[bool] = None, + paid_bursting_enabled: Optional[bool] = None, + paid_bursting_max_bandwidth_mibps: Optional[int] = None, + paid_bursting_max_iops: Optional[int] = None, + share_provisioned_iops: Optional[int] = None, + share_provisioned_bandwidth_mibps: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Sets properties for the specified share. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param quota: Specifies the maximum size of the share, in gigabytes. Default value is None. + :type quota: int + :param access_tier: Specifies the access tier of the share. Known values are: + "TransactionOptimized", "Hot", "Cool", and "Premium". Default value is None. + :type access_tier: str or ~azure.storage.fileshare.models.ShareAccessTier + :param root_squash: Root squash to set on the share. Only valid for NFS shares. Known values + are: "NoRootSquash", "RootSquash", and "AllSquash". Default value is None. + :type root_squash: str or ~azure.storage.fileshare.models.ShareRootSquash + :param enable_snapshot_virtual_directory_access: Default value is None. + :type enable_snapshot_virtual_directory_access: bool + :param paid_bursting_enabled: Optional. Boolean. Default if not specified is false. This + property enables paid bursting. Default value is None. + :type paid_bursting_enabled: bool + :param paid_bursting_max_bandwidth_mibps: Optional. Integer. Default if not specified is the + maximum throughput the file share can support. Current maximum for a file share is 10,340 + MiB/sec. Default value is None. + :type paid_bursting_max_bandwidth_mibps: int + :param paid_bursting_max_iops: Optional. Integer. Default if not specified is the maximum IOPS + the file share can support. Current maximum for a file share is 102,400 IOPS. Default value is + None. + :type paid_bursting_max_iops: int + :param share_provisioned_iops: Optional. Supported in version 2025-01-05 and later. Only + allowed for provisioned v2 file shares. Specifies the provisioned number of input/output + operations per second (IOPS) of the share. If this is not specified, the provisioned IOPS is + set to value calculated based on recommendation formula. Default value is None. + :type share_provisioned_iops: int + :param share_provisioned_bandwidth_mibps: Optional. Supported in version 2025-01-05 and later. + Only allowed for provisioned v2 file shares. Specifies the provisioned bandwidth of the share, + in mebibytes per second (MiBps). If this is not specified, the provisioned bandwidth is set to + value calculated based on recommendation formula. Default value is None. + :type share_provisioned_bandwidth_mibps: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_set_properties_request( + url=self._config.url, + timeout=timeout, + quota=quota, + access_tier=access_tier, + lease_id=_lease_id, + root_squash=root_squash, + enable_snapshot_virtual_directory_access=enable_snapshot_virtual_directory_access, + paid_bursting_enabled=paid_bursting_enabled, + paid_bursting_max_bandwidth_mibps=paid_bursting_max_bandwidth_mibps, + paid_bursting_max_iops=paid_bursting_max_iops, + share_provisioned_iops=share_provisioned_iops, + share_provisioned_bandwidth_mibps=share_provisioned_bandwidth_mibps, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-share-quota"] = self._deserialize("int", response.headers.get("x-ms-share-quota")) + response_headers["x-ms-share-provisioned-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-iops") + ) + response_headers["x-ms-share-provisioned-bandwidth-mibps"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-bandwidth-mibps") + ) + response_headers["x-ms-share-included-burst-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-included-burst-iops") + ) + response_headers["x-ms-share-max-burst-credits-for-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-max-burst-credits-for-iops") + ) + response_headers["x-ms-share-next-allowed-quota-downgrade-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-share-next-allowed-quota-downgrade-time") + ) + response_headers["x-ms-share-next-allowed-provisioned-iops-downgrade-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-share-next-allowed-provisioned-iops-downgrade-time") + ) + response_headers["x-ms-share-next-allowed-provisioned-bandwidth-downgrade-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-share-next-allowed-provisioned-bandwidth-downgrade-time") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def set_metadata( + self, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Sets one or more user-defined name-value pairs for the specified share. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["metadata"] = kwargs.pop("comp", _params.pop("comp", "metadata")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_set_metadata_request( + url=self._config.url, + timeout=timeout, + metadata=metadata, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def get_access_policy( + self, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> List[_models.SignedIdentifier]: + # pylint: disable=line-too-long + """Returns information about stored access policies specified on the share. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: list of SignedIdentifier or the result of cls(response) + :rtype: list[~azure.storage.fileshare.models.SignedIdentifier] + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["acl"] = kwargs.pop("comp", _params.pop("comp", "acl")) + cls: ClsType[List[_models.SignedIdentifier]] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_get_access_policy_request( + url=self._config.url, + timeout=timeout, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("[SignedIdentifier]", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def set_access_policy( + self, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + share_acl: Optional[List[_models.SignedIdentifier]] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Sets a stored access policy for use with shared access signatures. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :param share_acl: The ACL for the share. Default value is None. + :type share_acl: list[~azure.storage.fileshare.models.SignedIdentifier] + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["acl"] = kwargs.pop("comp", _params.pop("comp", "acl")) + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/xml")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + serialization_ctxt = {"xml": {"name": "SignedIdentifiers", "wrapped": True}} + if share_acl is not None: + _content = self._serialize.body( + share_acl, "[SignedIdentifier]", is_xml=True, serialization_ctxt=serialization_ctxt + ) + else: + _content = None + + _request = build_set_access_policy_request( + url=self._config.url, + timeout=timeout, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + content_type=content_type, + version=self._config.version, + content=_content, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace_async + async def get_statistics( + self, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> _models.ShareStats: + # pylint: disable=line-too-long + """Retrieves statistics related to the share. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: ShareStats or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.ShareStats + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["stats"] = kwargs.pop("comp", _params.pop("comp", "stats")) + cls: ClsType[_models.ShareStats] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_get_statistics_request( + url=self._config.url, + timeout=timeout, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("ShareStats", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace_async + async def restore( + self, + timeout: Optional[int] = None, + request_id_parameter: Optional[str] = None, + deleted_share_name: Optional[str] = None, + deleted_share_version: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Restores a previously deleted Share. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :param deleted_share_name: Specifies the name of the previously-deleted share. Default value is + None. + :type deleted_share_name: str + :param deleted_share_version: Specifies the version of the previously-deleted share. Default + value is None. + :type deleted_share_version: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["undelete"] = kwargs.pop("comp", _params.pop("comp", "undelete")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_restore_request( + url=self._config.url, + timeout=timeout, + request_id_parameter=request_id_parameter, + deleted_share_name=deleted_share_name, + deleted_share_version=deleted_share_version, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = await self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-share-quota"] = self._deserialize("int", response.headers.get("x-ms-share-quota")) + response_headers["x-ms-share-provisioned-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-iops") + ) + response_headers["x-ms-share-provisioned-bandwidth-mibps"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-bandwidth-mibps") + ) + response_headers["x-ms-share-included-burst-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-included-burst-iops") + ) + response_headers["x-ms-share-max-burst-credits-for-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-max-burst-credits-for-iops") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/models/__init__.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/models/__init__.py new file mode 100644 index 00000000..cb14cb30 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/models/__init__.py @@ -0,0 +1,130 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + + +from ._models_py3 import ( # type: ignore + AccessPolicy, + ClearRange, + CopyFileSmbInfo, + CorsRule, + DestinationLeaseAccessConditions, + DirectoryItem, + FileHTTPHeaders, + FileItem, + FileProperty, + FileRange, + FilesAndDirectoriesListSegment, + HandleItem, + LeaseAccessConditions, + ListFilesAndDirectoriesSegmentResponse, + ListHandlesResponse, + ListSharesResponse, + Metrics, + RetentionPolicy, + ShareFileRangeList, + ShareItemInternal, + SharePermission, + SharePropertiesInternal, + ShareProtocolSettings, + ShareSmbSettings, + ShareStats, + SignedIdentifier, + SmbMultichannel, + SourceLeaseAccessConditions, + SourceModifiedAccessConditions, + StorageError, + StorageServiceProperties, + StringEncoded, +) + +from ._azure_file_storage_enums import ( # type: ignore + AccessRight, + CopyStatusType, + DeleteSnapshotsOptionType, + FileLastWrittenMode, + FilePermissionFormat, + FileRangeWriteType, + LeaseDurationType, + LeaseStateType, + LeaseStatusType, + ListFilesIncludeType, + ListSharesIncludeType, + ModeCopyMode, + NfsFileType, + OwnerCopyMode, + PermissionCopyModeType, + ShareAccessTier, + ShareRootSquash, + ShareTokenIntent, + StorageErrorCode, +) +from ._patch import __all__ as _patch_all +from ._patch import * +from ._patch import patch_sdk as _patch_sdk + +__all__ = [ + "AccessPolicy", + "ClearRange", + "CopyFileSmbInfo", + "CorsRule", + "DestinationLeaseAccessConditions", + "DirectoryItem", + "FileHTTPHeaders", + "FileItem", + "FileProperty", + "FileRange", + "FilesAndDirectoriesListSegment", + "HandleItem", + "LeaseAccessConditions", + "ListFilesAndDirectoriesSegmentResponse", + "ListHandlesResponse", + "ListSharesResponse", + "Metrics", + "RetentionPolicy", + "ShareFileRangeList", + "ShareItemInternal", + "SharePermission", + "SharePropertiesInternal", + "ShareProtocolSettings", + "ShareSmbSettings", + "ShareStats", + "SignedIdentifier", + "SmbMultichannel", + "SourceLeaseAccessConditions", + "SourceModifiedAccessConditions", + "StorageError", + "StorageServiceProperties", + "StringEncoded", + "AccessRight", + "CopyStatusType", + "DeleteSnapshotsOptionType", + "FileLastWrittenMode", + "FilePermissionFormat", + "FileRangeWriteType", + "LeaseDurationType", + "LeaseStateType", + "LeaseStatusType", + "ListFilesIncludeType", + "ListSharesIncludeType", + "ModeCopyMode", + "NfsFileType", + "OwnerCopyMode", + "PermissionCopyModeType", + "ShareAccessTier", + "ShareRootSquash", + "ShareTokenIntent", + "StorageErrorCode", +] +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore +_patch_sdk() diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/models/_azure_file_storage_enums.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/models/_azure_file_storage_enums.py new file mode 100644 index 00000000..efc7a7fe --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/models/_azure_file_storage_enums.py @@ -0,0 +1,222 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +from enum import Enum +from azure.core import CaseInsensitiveEnumMeta + + +class AccessRight(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Access rights of the access policy.""" + + READ = "Read" + WRITE = "Write" + DELETE = "Delete" + + +class CopyStatusType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """CopyStatusType.""" + + PENDING = "pending" + SUCCESS = "success" + ABORTED = "aborted" + FAILED = "failed" + + +class DeleteSnapshotsOptionType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """DeleteSnapshotsOptionType.""" + + INCLUDE = "include" + INCLUDE_LEASED = "include-leased" + + +class FileLastWrittenMode(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """FileLastWrittenMode.""" + + NOW = "Now" + PRESERVE = "Preserve" + + +class FilePermissionFormat(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """FilePermissionFormat.""" + + SDDL = "Sddl" + BINARY = "Binary" + + +class FileRangeWriteType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """FileRangeWriteType.""" + + UPDATE = "update" + CLEAR = "clear" + + +class LeaseDurationType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """When a share is leased, specifies whether the lease is of infinite or fixed duration.""" + + INFINITE = "infinite" + FIXED = "fixed" + + +class LeaseStateType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Lease state of the share.""" + + AVAILABLE = "available" + LEASED = "leased" + EXPIRED = "expired" + BREAKING = "breaking" + BROKEN = "broken" + + +class LeaseStatusType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """The current lease status of the share.""" + + LOCKED = "locked" + UNLOCKED = "unlocked" + + +class ListFilesIncludeType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """ListFilesIncludeType.""" + + TIMESTAMPS = "Timestamps" + ETAG = "Etag" + ATTRIBUTES = "Attributes" + PERMISSION_KEY = "PermissionKey" + + +class ListSharesIncludeType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """ListSharesIncludeType.""" + + SNAPSHOTS = "snapshots" + METADATA = "metadata" + DELETED = "deleted" + + +class ModeCopyMode(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """ModeCopyMode.""" + + SOURCE = "source" + OVERRIDE = "override" + + +class NfsFileType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """NfsFileType.""" + + REGULAR = "Regular" + DIRECTORY = "Directory" + SYM_LINK = "SymLink" + + +class OwnerCopyMode(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """OwnerCopyMode.""" + + SOURCE = "source" + OVERRIDE = "override" + + +class PermissionCopyModeType(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """PermissionCopyModeType.""" + + SOURCE = "source" + OVERRIDE = "override" + + +class ShareAccessTier(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """ShareAccessTier.""" + + TRANSACTION_OPTIMIZED = "TransactionOptimized" + HOT = "Hot" + COOL = "Cool" + PREMIUM = "Premium" + + +class ShareRootSquash(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """ShareRootSquash.""" + + NO_ROOT_SQUASH = "NoRootSquash" + ROOT_SQUASH = "RootSquash" + ALL_SQUASH = "AllSquash" + + +class ShareTokenIntent(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """ShareTokenIntent.""" + + BACKUP = "backup" + + +class StorageErrorCode(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Error codes returned by the service.""" + + ACCOUNT_ALREADY_EXISTS = "AccountAlreadyExists" + ACCOUNT_BEING_CREATED = "AccountBeingCreated" + ACCOUNT_IS_DISABLED = "AccountIsDisabled" + AUTHENTICATION_FAILED = "AuthenticationFailed" + AUTHORIZATION_FAILURE = "AuthorizationFailure" + CONDITION_HEADERS_NOT_SUPPORTED = "ConditionHeadersNotSupported" + CONDITION_NOT_MET = "ConditionNotMet" + EMPTY_METADATA_KEY = "EmptyMetadataKey" + FILE_SHARE_PROVISIONED_BANDWIDTH_DOWNGRADE_NOT_ALLOWED = "FileShareProvisionedBandwidthDowngradeNotAllowed" + FILE_SHARE_PROVISIONED_IOPS_DOWNGRADE_NOT_ALLOWED = "FileShareProvisionedIopsDowngradeNotAllowed" + INSUFFICIENT_ACCOUNT_PERMISSIONS = "InsufficientAccountPermissions" + INTERNAL_ERROR = "InternalError" + INVALID_AUTHENTICATION_INFO = "InvalidAuthenticationInfo" + INVALID_HEADER_VALUE = "InvalidHeaderValue" + INVALID_HTTP_VERB = "InvalidHttpVerb" + INVALID_INPUT = "InvalidInput" + INVALID_MD5 = "InvalidMd5" + INVALID_METADATA = "InvalidMetadata" + INVALID_QUERY_PARAMETER_VALUE = "InvalidQueryParameterValue" + INVALID_RANGE = "InvalidRange" + INVALID_RESOURCE_NAME = "InvalidResourceName" + INVALID_URI = "InvalidUri" + INVALID_XML_DOCUMENT = "InvalidXmlDocument" + INVALID_XML_NODE_VALUE = "InvalidXmlNodeValue" + MD5_MISMATCH = "Md5Mismatch" + METADATA_TOO_LARGE = "MetadataTooLarge" + MISSING_CONTENT_LENGTH_HEADER = "MissingContentLengthHeader" + MISSING_REQUIRED_QUERY_PARAMETER = "MissingRequiredQueryParameter" + MISSING_REQUIRED_HEADER = "MissingRequiredHeader" + MISSING_REQUIRED_XML_NODE = "MissingRequiredXmlNode" + MULTIPLE_CONDITION_HEADERS_NOT_SUPPORTED = "MultipleConditionHeadersNotSupported" + OPERATION_TIMED_OUT = "OperationTimedOut" + OUT_OF_RANGE_INPUT = "OutOfRangeInput" + OUT_OF_RANGE_QUERY_PARAMETER_VALUE = "OutOfRangeQueryParameterValue" + REQUEST_BODY_TOO_LARGE = "RequestBodyTooLarge" + RESOURCE_TYPE_MISMATCH = "ResourceTypeMismatch" + REQUEST_URL_FAILED_TO_PARSE = "RequestUrlFailedToParse" + RESOURCE_ALREADY_EXISTS = "ResourceAlreadyExists" + RESOURCE_NOT_FOUND = "ResourceNotFound" + SERVER_BUSY = "ServerBusy" + UNSUPPORTED_HEADER = "UnsupportedHeader" + UNSUPPORTED_XML_NODE = "UnsupportedXmlNode" + UNSUPPORTED_QUERY_PARAMETER = "UnsupportedQueryParameter" + UNSUPPORTED_HTTP_VERB = "UnsupportedHttpVerb" + CANNOT_DELETE_FILE_OR_DIRECTORY = "CannotDeleteFileOrDirectory" + CLIENT_CACHE_FLUSH_DELAY = "ClientCacheFlushDelay" + DELETE_PENDING = "DeletePending" + DIRECTORY_NOT_EMPTY = "DirectoryNotEmpty" + FILE_LOCK_CONFLICT = "FileLockConflict" + INVALID_FILE_OR_DIRECTORY_PATH_NAME = "InvalidFileOrDirectoryPathName" + PARENT_NOT_FOUND = "ParentNotFound" + READ_ONLY_ATTRIBUTE = "ReadOnlyAttribute" + SHARE_ALREADY_EXISTS = "ShareAlreadyExists" + SHARE_BEING_DELETED = "ShareBeingDeleted" + SHARE_DISABLED = "ShareDisabled" + SHARE_NOT_FOUND = "ShareNotFound" + SHARING_VIOLATION = "SharingViolation" + SHARE_SNAPSHOT_IN_PROGRESS = "ShareSnapshotInProgress" + SHARE_SNAPSHOT_COUNT_EXCEEDED = "ShareSnapshotCountExceeded" + SHARE_SNAPSHOT_OPERATION_NOT_SUPPORTED = "ShareSnapshotOperationNotSupported" + SHARE_HAS_SNAPSHOTS = "ShareHasSnapshots" + PREVIOUS_SNAPSHOT_NOT_FOUND = "PreviousSnapshotNotFound" + CONTAINER_QUOTA_DOWNGRADE_NOT_ALLOWED = "ContainerQuotaDowngradeNotAllowed" + AUTHORIZATION_SOURCE_IP_MISMATCH = "AuthorizationSourceIPMismatch" + AUTHORIZATION_PROTOCOL_MISMATCH = "AuthorizationProtocolMismatch" + AUTHORIZATION_PERMISSION_MISMATCH = "AuthorizationPermissionMismatch" + AUTHORIZATION_SERVICE_MISMATCH = "AuthorizationServiceMismatch" + AUTHORIZATION_RESOURCE_TYPE_MISMATCH = "AuthorizationResourceTypeMismatch" + FEATURE_VERSION_MISMATCH = "FeatureVersionMismatch" diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/models/_models_py3.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/models/_models_py3.py new file mode 100644 index 00000000..61fe75ce --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/models/_models_py3.py @@ -0,0 +1,1711 @@ +# pylint: disable=too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- + +import datetime +from typing import Any, Dict, List, Optional, TYPE_CHECKING, Union + +from .. import _serialization + +if TYPE_CHECKING: + from .. import models as _models + + +class AccessPolicy(_serialization.Model): + """An Access policy. + + :ivar start: The date-time the policy is active. + :vartype start: str + :ivar expiry: The date-time the policy expires. + :vartype expiry: str + :ivar permission: The permissions for the ACL policy. + :vartype permission: str + """ + + _attribute_map = { + "start": {"key": "Start", "type": "str"}, + "expiry": {"key": "Expiry", "type": "str"}, + "permission": {"key": "Permission", "type": "str"}, + } + + def __init__( + self, + *, + start: Optional[str] = None, + expiry: Optional[str] = None, + permission: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword start: The date-time the policy is active. + :paramtype start: str + :keyword expiry: The date-time the policy expires. + :paramtype expiry: str + :keyword permission: The permissions for the ACL policy. + :paramtype permission: str + """ + super().__init__(**kwargs) + self.start = start + self.expiry = expiry + self.permission = permission + + +class ClearRange(_serialization.Model): + """ClearRange. + + All required parameters must be populated in order to send to server. + + :ivar start: Required. + :vartype start: int + :ivar end: Required. + :vartype end: int + """ + + _validation = { + "start": {"required": True}, + "end": {"required": True}, + } + + _attribute_map = { + "start": {"key": "Start", "type": "int", "xml": {"name": "Start"}}, + "end": {"key": "End", "type": "int", "xml": {"name": "End"}}, + } + _xml_map = {"name": "ClearRange"} + + def __init__(self, *, start: int, end: int, **kwargs: Any) -> None: + """ + :keyword start: Required. + :paramtype start: int + :keyword end: Required. + :paramtype end: int + """ + super().__init__(**kwargs) + self.start = start + self.end = end + + +class CopyFileSmbInfo(_serialization.Model): + """Parameter group. + + :ivar file_attributes: Specifies either the option to copy file attributes from a source + file(source) to a target file or a list of attributes to set on a target file. + :vartype file_attributes: str + :ivar file_creation_time: Specifies either the option to copy file creation time from a source + file(source) to a target file or a time value in ISO 8601 format to set as creation time on a + target file. + :vartype file_creation_time: str + :ivar file_last_write_time: Specifies either the option to copy file last write time from a + source file(source) to a target file or a time value in ISO 8601 format to set as last write + time on a target file. + :vartype file_last_write_time: str + :ivar file_change_time: Specifies either the option to copy file last write time from a source + file(source) to a target file or a time value in ISO 8601 format to set as last write time on a + target file. + :vartype file_change_time: str + :ivar file_permission_copy_mode: Specifies the option to copy file security descriptor from + source file or to set it using the value which is defined by the header value of + x-ms-file-permission or x-ms-file-permission-key. Known values are: "source" and "override". + :vartype file_permission_copy_mode: str or + ~azure.storage.fileshare.models.PermissionCopyModeType + :ivar ignore_read_only: Specifies the option to overwrite the target file if it already exists + and has read-only attribute set. + :vartype ignore_read_only: bool + :ivar set_archive_attribute: Specifies the option to set archive attribute on a target file. + True means archive attribute will be set on a target file despite attribute overrides or a + source file state. + :vartype set_archive_attribute: bool + """ + + _attribute_map = { + "file_attributes": {"key": "fileAttributes", "type": "str"}, + "file_creation_time": {"key": "fileCreationTime", "type": "str"}, + "file_last_write_time": {"key": "fileLastWriteTime", "type": "str"}, + "file_change_time": {"key": "fileChangeTime", "type": "str"}, + "file_permission_copy_mode": {"key": "filePermissionCopyMode", "type": "str"}, + "ignore_read_only": {"key": "ignoreReadOnly", "type": "bool"}, + "set_archive_attribute": {"key": "setArchiveAttribute", "type": "bool"}, + } + + def __init__( + self, + *, + file_attributes: Optional[str] = None, + file_creation_time: Optional[str] = None, + file_last_write_time: Optional[str] = None, + file_change_time: Optional[str] = None, + file_permission_copy_mode: Optional[Union[str, "_models.PermissionCopyModeType"]] = None, + ignore_read_only: Optional[bool] = None, + set_archive_attribute: Optional[bool] = None, + **kwargs: Any + ) -> None: + """ + :keyword file_attributes: Specifies either the option to copy file attributes from a source + file(source) to a target file or a list of attributes to set on a target file. + :paramtype file_attributes: str + :keyword file_creation_time: Specifies either the option to copy file creation time from a + source file(source) to a target file or a time value in ISO 8601 format to set as creation time + on a target file. + :paramtype file_creation_time: str + :keyword file_last_write_time: Specifies either the option to copy file last write time from a + source file(source) to a target file or a time value in ISO 8601 format to set as last write + time on a target file. + :paramtype file_last_write_time: str + :keyword file_change_time: Specifies either the option to copy file last write time from a + source file(source) to a target file or a time value in ISO 8601 format to set as last write + time on a target file. + :paramtype file_change_time: str + :keyword file_permission_copy_mode: Specifies the option to copy file security descriptor from + source file or to set it using the value which is defined by the header value of + x-ms-file-permission or x-ms-file-permission-key. Known values are: "source" and "override". + :paramtype file_permission_copy_mode: str or + ~azure.storage.fileshare.models.PermissionCopyModeType + :keyword ignore_read_only: Specifies the option to overwrite the target file if it already + exists and has read-only attribute set. + :paramtype ignore_read_only: bool + :keyword set_archive_attribute: Specifies the option to set archive attribute on a target file. + True means archive attribute will be set on a target file despite attribute overrides or a + source file state. + :paramtype set_archive_attribute: bool + """ + super().__init__(**kwargs) + self.file_attributes = file_attributes + self.file_creation_time = file_creation_time + self.file_last_write_time = file_last_write_time + self.file_change_time = file_change_time + self.file_permission_copy_mode = file_permission_copy_mode + self.ignore_read_only = ignore_read_only + self.set_archive_attribute = set_archive_attribute + + +class CorsRule(_serialization.Model): + """CORS is an HTTP feature that enables a web application running under one domain to access + resources in another domain. Web browsers implement a security restriction known as same-origin + policy that prevents a web page from calling APIs in a different domain; CORS provides a secure + way to allow one domain (the origin domain) to call APIs in another domain. + + All required parameters must be populated in order to send to server. + + :ivar allowed_origins: The origin domains that are permitted to make a request against the + storage service via CORS. The origin domain is the domain from which the request originates. + Note that the origin must be an exact case-sensitive match with the origin that the user age + sends to the service. You can also use the wildcard character '*' to allow all origin domains + to make requests via CORS. Required. + :vartype allowed_origins: str + :ivar allowed_methods: The methods (HTTP request verbs) that the origin domain may use for a + CORS request. (comma separated). Required. + :vartype allowed_methods: str + :ivar allowed_headers: The request headers that the origin domain may specify on the CORS + request. Required. + :vartype allowed_headers: str + :ivar exposed_headers: The response headers that may be sent in the response to the CORS + request and exposed by the browser to the request issuer. Required. + :vartype exposed_headers: str + :ivar max_age_in_seconds: The maximum amount time that a browser should cache the preflight + OPTIONS request. Required. + :vartype max_age_in_seconds: int + """ + + _validation = { + "allowed_origins": {"required": True}, + "allowed_methods": {"required": True}, + "allowed_headers": {"required": True}, + "exposed_headers": {"required": True}, + "max_age_in_seconds": {"required": True, "minimum": 0}, + } + + _attribute_map = { + "allowed_origins": {"key": "AllowedOrigins", "type": "str"}, + "allowed_methods": {"key": "AllowedMethods", "type": "str"}, + "allowed_headers": {"key": "AllowedHeaders", "type": "str"}, + "exposed_headers": {"key": "ExposedHeaders", "type": "str"}, + "max_age_in_seconds": {"key": "MaxAgeInSeconds", "type": "int"}, + } + + def __init__( + self, + *, + allowed_origins: str, + allowed_methods: str, + allowed_headers: str, + exposed_headers: str, + max_age_in_seconds: int, + **kwargs: Any + ) -> None: + """ + :keyword allowed_origins: The origin domains that are permitted to make a request against the + storage service via CORS. The origin domain is the domain from which the request originates. + Note that the origin must be an exact case-sensitive match with the origin that the user age + sends to the service. You can also use the wildcard character '*' to allow all origin domains + to make requests via CORS. Required. + :paramtype allowed_origins: str + :keyword allowed_methods: The methods (HTTP request verbs) that the origin domain may use for a + CORS request. (comma separated). Required. + :paramtype allowed_methods: str + :keyword allowed_headers: The request headers that the origin domain may specify on the CORS + request. Required. + :paramtype allowed_headers: str + :keyword exposed_headers: The response headers that may be sent in the response to the CORS + request and exposed by the browser to the request issuer. Required. + :paramtype exposed_headers: str + :keyword max_age_in_seconds: The maximum amount time that a browser should cache the preflight + OPTIONS request. Required. + :paramtype max_age_in_seconds: int + """ + super().__init__(**kwargs) + self.allowed_origins = allowed_origins + self.allowed_methods = allowed_methods + self.allowed_headers = allowed_headers + self.exposed_headers = exposed_headers + self.max_age_in_seconds = max_age_in_seconds + + +class DestinationLeaseAccessConditions(_serialization.Model): + """Parameter group. + + :ivar destination_lease_id: Required if the destination file has an active infinite lease. The + lease ID specified for this header must match the lease ID of the destination file. If the + request does not include the lease ID or it is not valid, the operation fails with status code + 412 (Precondition Failed). If this header is specified and the destination file does not + currently have an active lease, the operation will also fail with status code 412 (Precondition + Failed). + :vartype destination_lease_id: str + """ + + _attribute_map = { + "destination_lease_id": {"key": "destinationLeaseId", "type": "str"}, + } + + def __init__(self, *, destination_lease_id: Optional[str] = None, **kwargs: Any) -> None: + """ + :keyword destination_lease_id: Required if the destination file has an active infinite lease. + The lease ID specified for this header must match the lease ID of the destination file. If the + request does not include the lease ID or it is not valid, the operation fails with status code + 412 (Precondition Failed). If this header is specified and the destination file does not + currently have an active lease, the operation will also fail with status code 412 (Precondition + Failed). + :paramtype destination_lease_id: str + """ + super().__init__(**kwargs) + self.destination_lease_id = destination_lease_id + + +class DirectoryItem(_serialization.Model): + """A listed directory item. + + All required parameters must be populated in order to send to server. + + :ivar name: Required. + :vartype name: ~azure.storage.fileshare.models.StringEncoded + :ivar file_id: + :vartype file_id: str + :ivar properties: File properties. + :vartype properties: ~azure.storage.fileshare.models.FileProperty + :ivar attributes: + :vartype attributes: str + :ivar permission_key: + :vartype permission_key: str + """ + + _validation = { + "name": {"required": True}, + } + + _attribute_map = { + "name": {"key": "Name", "type": "StringEncoded"}, + "file_id": {"key": "FileId", "type": "str"}, + "properties": {"key": "Properties", "type": "FileProperty"}, + "attributes": {"key": "Attributes", "type": "str"}, + "permission_key": {"key": "PermissionKey", "type": "str"}, + } + _xml_map = {"name": "Directory"} + + def __init__( + self, + *, + name: "_models.StringEncoded", + file_id: Optional[str] = None, + properties: Optional["_models.FileProperty"] = None, + attributes: Optional[str] = None, + permission_key: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword name: Required. + :paramtype name: ~azure.storage.fileshare.models.StringEncoded + :keyword file_id: + :paramtype file_id: str + :keyword properties: File properties. + :paramtype properties: ~azure.storage.fileshare.models.FileProperty + :keyword attributes: + :paramtype attributes: str + :keyword permission_key: + :paramtype permission_key: str + """ + super().__init__(**kwargs) + self.name = name + self.file_id = file_id + self.properties = properties + self.attributes = attributes + self.permission_key = permission_key + + +class FileHTTPHeaders(_serialization.Model): + """Parameter group. + + :ivar file_content_type: Sets the MIME content type of the file. The default type is + 'application/octet-stream'. + :vartype file_content_type: str + :ivar file_content_encoding: Specifies which content encodings have been applied to the file. + :vartype file_content_encoding: str + :ivar file_content_language: Specifies the natural languages used by this resource. + :vartype file_content_language: str + :ivar file_cache_control: Sets the file's cache control. The File service stores this value but + does not use or modify it. + :vartype file_cache_control: str + :ivar file_content_md5: Sets the file's MD5 hash. + :vartype file_content_md5: bytes + :ivar file_content_disposition: Sets the file's Content-Disposition header. + :vartype file_content_disposition: str + """ + + _attribute_map = { + "file_content_type": {"key": "fileContentType", "type": "str"}, + "file_content_encoding": {"key": "fileContentEncoding", "type": "str"}, + "file_content_language": {"key": "fileContentLanguage", "type": "str"}, + "file_cache_control": {"key": "fileCacheControl", "type": "str"}, + "file_content_md5": {"key": "fileContentMD5", "type": "bytearray"}, + "file_content_disposition": {"key": "fileContentDisposition", "type": "str"}, + } + + def __init__( + self, + *, + file_content_type: Optional[str] = None, + file_content_encoding: Optional[str] = None, + file_content_language: Optional[str] = None, + file_cache_control: Optional[str] = None, + file_content_md5: Optional[bytes] = None, + file_content_disposition: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword file_content_type: Sets the MIME content type of the file. The default type is + 'application/octet-stream'. + :paramtype file_content_type: str + :keyword file_content_encoding: Specifies which content encodings have been applied to the + file. + :paramtype file_content_encoding: str + :keyword file_content_language: Specifies the natural languages used by this resource. + :paramtype file_content_language: str + :keyword file_cache_control: Sets the file's cache control. The File service stores this value + but does not use or modify it. + :paramtype file_cache_control: str + :keyword file_content_md5: Sets the file's MD5 hash. + :paramtype file_content_md5: bytes + :keyword file_content_disposition: Sets the file's Content-Disposition header. + :paramtype file_content_disposition: str + """ + super().__init__(**kwargs) + self.file_content_type = file_content_type + self.file_content_encoding = file_content_encoding + self.file_content_language = file_content_language + self.file_cache_control = file_cache_control + self.file_content_md5 = file_content_md5 + self.file_content_disposition = file_content_disposition + + +class FileItem(_serialization.Model): + """A listed file item. + + All required parameters must be populated in order to send to server. + + :ivar name: Required. + :vartype name: ~azure.storage.fileshare.models.StringEncoded + :ivar file_id: + :vartype file_id: str + :ivar properties: File properties. Required. + :vartype properties: ~azure.storage.fileshare.models.FileProperty + :ivar attributes: + :vartype attributes: str + :ivar permission_key: + :vartype permission_key: str + """ + + _validation = { + "name": {"required": True}, + "properties": {"required": True}, + } + + _attribute_map = { + "name": {"key": "Name", "type": "StringEncoded"}, + "file_id": {"key": "FileId", "type": "str"}, + "properties": {"key": "Properties", "type": "FileProperty"}, + "attributes": {"key": "Attributes", "type": "str"}, + "permission_key": {"key": "PermissionKey", "type": "str"}, + } + _xml_map = {"name": "File"} + + def __init__( + self, + *, + name: "_models.StringEncoded", + properties: "_models.FileProperty", + file_id: Optional[str] = None, + attributes: Optional[str] = None, + permission_key: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword name: Required. + :paramtype name: ~azure.storage.fileshare.models.StringEncoded + :keyword file_id: + :paramtype file_id: str + :keyword properties: File properties. Required. + :paramtype properties: ~azure.storage.fileshare.models.FileProperty + :keyword attributes: + :paramtype attributes: str + :keyword permission_key: + :paramtype permission_key: str + """ + super().__init__(**kwargs) + self.name = name + self.file_id = file_id + self.properties = properties + self.attributes = attributes + self.permission_key = permission_key + + +class FileProperty(_serialization.Model): + """File properties. + + All required parameters must be populated in order to send to server. + + :ivar content_length: Content length of the file. This value may not be up-to-date since an SMB + client may have modified the file locally. The value of Content-Length may not reflect that + fact until the handle is closed or the op-lock is broken. To retrieve current property values, + call Get File Properties. Required. + :vartype content_length: int + :ivar creation_time: + :vartype creation_time: ~datetime.datetime + :ivar last_access_time: + :vartype last_access_time: ~datetime.datetime + :ivar last_write_time: + :vartype last_write_time: ~datetime.datetime + :ivar change_time: + :vartype change_time: ~datetime.datetime + :ivar last_modified: + :vartype last_modified: ~datetime.datetime + :ivar etag: + :vartype etag: str + """ + + _validation = { + "content_length": {"required": True}, + } + + _attribute_map = { + "content_length": {"key": "Content-Length", "type": "int"}, + "creation_time": {"key": "CreationTime", "type": "iso-8601"}, + "last_access_time": {"key": "LastAccessTime", "type": "iso-8601"}, + "last_write_time": {"key": "LastWriteTime", "type": "iso-8601"}, + "change_time": {"key": "ChangeTime", "type": "iso-8601"}, + "last_modified": {"key": "Last-Modified", "type": "rfc-1123"}, + "etag": {"key": "Etag", "type": "str"}, + } + + def __init__( + self, + *, + content_length: int, + creation_time: Optional[datetime.datetime] = None, + last_access_time: Optional[datetime.datetime] = None, + last_write_time: Optional[datetime.datetime] = None, + change_time: Optional[datetime.datetime] = None, + last_modified: Optional[datetime.datetime] = None, + etag: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword content_length: Content length of the file. This value may not be up-to-date since an + SMB client may have modified the file locally. The value of Content-Length may not reflect that + fact until the handle is closed or the op-lock is broken. To retrieve current property values, + call Get File Properties. Required. + :paramtype content_length: int + :keyword creation_time: + :paramtype creation_time: ~datetime.datetime + :keyword last_access_time: + :paramtype last_access_time: ~datetime.datetime + :keyword last_write_time: + :paramtype last_write_time: ~datetime.datetime + :keyword change_time: + :paramtype change_time: ~datetime.datetime + :keyword last_modified: + :paramtype last_modified: ~datetime.datetime + :keyword etag: + :paramtype etag: str + """ + super().__init__(**kwargs) + self.content_length = content_length + self.creation_time = creation_time + self.last_access_time = last_access_time + self.last_write_time = last_write_time + self.change_time = change_time + self.last_modified = last_modified + self.etag = etag + + +class FileRange(_serialization.Model): + """An Azure Storage file range. + + All required parameters must be populated in order to send to server. + + :ivar start: Start of the range. Required. + :vartype start: int + :ivar end: End of the range. Required. + :vartype end: int + """ + + _validation = { + "start": {"required": True}, + "end": {"required": True}, + } + + _attribute_map = { + "start": {"key": "Start", "type": "int"}, + "end": {"key": "End", "type": "int"}, + } + _xml_map = {"name": "Range"} + + def __init__(self, *, start: int, end: int, **kwargs: Any) -> None: + """ + :keyword start: Start of the range. Required. + :paramtype start: int + :keyword end: End of the range. Required. + :paramtype end: int + """ + super().__init__(**kwargs) + self.start = start + self.end = end + + +class FilesAndDirectoriesListSegment(_serialization.Model): + """Abstract for entries that can be listed from Directory. + + All required parameters must be populated in order to send to server. + + :ivar directory_items: Required. + :vartype directory_items: list[~azure.storage.fileshare.models.DirectoryItem] + :ivar file_items: Required. + :vartype file_items: list[~azure.storage.fileshare.models.FileItem] + """ + + _validation = { + "directory_items": {"required": True}, + "file_items": {"required": True}, + } + + _attribute_map = { + "directory_items": {"key": "DirectoryItems", "type": "[DirectoryItem]", "xml": {"itemsName": "Directory"}}, + "file_items": {"key": "FileItems", "type": "[FileItem]", "xml": {"itemsName": "File"}}, + } + _xml_map = {"name": "Entries"} + + def __init__( + self, *, directory_items: List["_models.DirectoryItem"], file_items: List["_models.FileItem"], **kwargs: Any + ) -> None: + """ + :keyword directory_items: Required. + :paramtype directory_items: list[~azure.storage.fileshare.models.DirectoryItem] + :keyword file_items: Required. + :paramtype file_items: list[~azure.storage.fileshare.models.FileItem] + """ + super().__init__(**kwargs) + self.directory_items = directory_items + self.file_items = file_items + + +class HandleItem(_serialization.Model): + """A listed Azure Storage handle item. + + All required parameters must be populated in order to send to server. + + :ivar handle_id: XSMB service handle ID. Required. + :vartype handle_id: str + :ivar path: Required. + :vartype path: ~azure.storage.fileshare.models.StringEncoded + :ivar file_id: FileId uniquely identifies the file or directory. Required. + :vartype file_id: str + :ivar parent_id: ParentId uniquely identifies the parent directory of the object. + :vartype parent_id: str + :ivar session_id: SMB session ID in context of which the file handle was opened. Required. + :vartype session_id: str + :ivar client_ip: Client IP that opened the handle. Required. + :vartype client_ip: str + :ivar client_name: Name of the client machine where the share is being mounted. Required. + :vartype client_name: str + :ivar open_time: Time when the session that previously opened the handle has last been + reconnected. (UTC). Required. + :vartype open_time: ~datetime.datetime + :ivar last_reconnect_time: Time handle was last connected to (UTC). + :vartype last_reconnect_time: ~datetime.datetime + :ivar access_right_list: + :vartype access_right_list: list[str or ~azure.storage.fileshare.models.AccessRight] + """ + + _validation = { + "handle_id": {"required": True}, + "path": {"required": True}, + "file_id": {"required": True}, + "session_id": {"required": True}, + "client_ip": {"required": True}, + "client_name": {"required": True}, + "open_time": {"required": True}, + } + + _attribute_map = { + "handle_id": {"key": "HandleId", "type": "str"}, + "path": {"key": "Path", "type": "StringEncoded"}, + "file_id": {"key": "FileId", "type": "str"}, + "parent_id": {"key": "ParentId", "type": "str"}, + "session_id": {"key": "SessionId", "type": "str"}, + "client_ip": {"key": "ClientIp", "type": "str"}, + "client_name": {"key": "ClientName", "type": "str"}, + "open_time": {"key": "OpenTime", "type": "rfc-1123"}, + "last_reconnect_time": {"key": "LastReconnectTime", "type": "rfc-1123"}, + "access_right_list": {"key": "AccessRightList", "type": "[str]", "xml": {"wrapped": True}}, + } + _xml_map = {"name": "Handle"} + + def __init__( + self, + *, + handle_id: str, + path: "_models.StringEncoded", + file_id: str, + session_id: str, + client_ip: str, + client_name: str, + open_time: datetime.datetime, + parent_id: Optional[str] = None, + last_reconnect_time: Optional[datetime.datetime] = None, + access_right_list: Optional[List[Union[str, "_models.AccessRight"]]] = None, + **kwargs: Any + ) -> None: + """ + :keyword handle_id: XSMB service handle ID. Required. + :paramtype handle_id: str + :keyword path: Required. + :paramtype path: ~azure.storage.fileshare.models.StringEncoded + :keyword file_id: FileId uniquely identifies the file or directory. Required. + :paramtype file_id: str + :keyword parent_id: ParentId uniquely identifies the parent directory of the object. + :paramtype parent_id: str + :keyword session_id: SMB session ID in context of which the file handle was opened. Required. + :paramtype session_id: str + :keyword client_ip: Client IP that opened the handle. Required. + :paramtype client_ip: str + :keyword client_name: Name of the client machine where the share is being mounted. Required. + :paramtype client_name: str + :keyword open_time: Time when the session that previously opened the handle has last been + reconnected. (UTC). Required. + :paramtype open_time: ~datetime.datetime + :keyword last_reconnect_time: Time handle was last connected to (UTC). + :paramtype last_reconnect_time: ~datetime.datetime + :keyword access_right_list: + :paramtype access_right_list: list[str or ~azure.storage.fileshare.models.AccessRight] + """ + super().__init__(**kwargs) + self.handle_id = handle_id + self.path = path + self.file_id = file_id + self.parent_id = parent_id + self.session_id = session_id + self.client_ip = client_ip + self.client_name = client_name + self.open_time = open_time + self.last_reconnect_time = last_reconnect_time + self.access_right_list = access_right_list + + +class LeaseAccessConditions(_serialization.Model): + """Parameter group. + + :ivar lease_id: If specified, the operation only succeeds if the resource's lease is active and + matches this ID. + :vartype lease_id: str + """ + + _attribute_map = { + "lease_id": {"key": "leaseId", "type": "str"}, + } + + def __init__(self, *, lease_id: Optional[str] = None, **kwargs: Any) -> None: + """ + :keyword lease_id: If specified, the operation only succeeds if the resource's lease is active + and matches this ID. + :paramtype lease_id: str + """ + super().__init__(**kwargs) + self.lease_id = lease_id + + +class ListFilesAndDirectoriesSegmentResponse(_serialization.Model): + """An enumeration of directories and files. + + All required parameters must be populated in order to send to server. + + :ivar service_endpoint: Required. + :vartype service_endpoint: str + :ivar share_name: Required. + :vartype share_name: str + :ivar share_snapshot: + :vartype share_snapshot: str + :ivar encoded: + :vartype encoded: bool + :ivar directory_path: Required. + :vartype directory_path: str + :ivar prefix: Required. + :vartype prefix: ~azure.storage.fileshare.models.StringEncoded + :ivar marker: + :vartype marker: str + :ivar max_results: + :vartype max_results: int + :ivar segment: Abstract for entries that can be listed from Directory. Required. + :vartype segment: ~azure.storage.fileshare.models.FilesAndDirectoriesListSegment + :ivar next_marker: Required. + :vartype next_marker: str + :ivar directory_id: + :vartype directory_id: str + """ + + _validation = { + "service_endpoint": {"required": True}, + "share_name": {"required": True}, + "directory_path": {"required": True}, + "prefix": {"required": True}, + "segment": {"required": True}, + "next_marker": {"required": True}, + } + + _attribute_map = { + "service_endpoint": {"key": "ServiceEndpoint", "type": "str", "xml": {"attr": True}}, + "share_name": {"key": "ShareName", "type": "str", "xml": {"attr": True}}, + "share_snapshot": {"key": "ShareSnapshot", "type": "str", "xml": {"attr": True}}, + "encoded": {"key": "Encoded", "type": "bool", "xml": {"attr": True}}, + "directory_path": {"key": "DirectoryPath", "type": "str", "xml": {"attr": True}}, + "prefix": {"key": "Prefix", "type": "StringEncoded"}, + "marker": {"key": "Marker", "type": "str"}, + "max_results": {"key": "MaxResults", "type": "int"}, + "segment": {"key": "Segment", "type": "FilesAndDirectoriesListSegment"}, + "next_marker": {"key": "NextMarker", "type": "str"}, + "directory_id": {"key": "DirectoryId", "type": "str"}, + } + _xml_map = {"name": "EnumerationResults"} + + def __init__( + self, + *, + service_endpoint: str, + share_name: str, + directory_path: str, + prefix: "_models.StringEncoded", + segment: "_models.FilesAndDirectoriesListSegment", + next_marker: str, + share_snapshot: Optional[str] = None, + encoded: Optional[bool] = None, + marker: Optional[str] = None, + max_results: Optional[int] = None, + directory_id: Optional[str] = None, + **kwargs: Any + ) -> None: + """ + :keyword service_endpoint: Required. + :paramtype service_endpoint: str + :keyword share_name: Required. + :paramtype share_name: str + :keyword share_snapshot: + :paramtype share_snapshot: str + :keyword encoded: + :paramtype encoded: bool + :keyword directory_path: Required. + :paramtype directory_path: str + :keyword prefix: Required. + :paramtype prefix: ~azure.storage.fileshare.models.StringEncoded + :keyword marker: + :paramtype marker: str + :keyword max_results: + :paramtype max_results: int + :keyword segment: Abstract for entries that can be listed from Directory. Required. + :paramtype segment: ~azure.storage.fileshare.models.FilesAndDirectoriesListSegment + :keyword next_marker: Required. + :paramtype next_marker: str + :keyword directory_id: + :paramtype directory_id: str + """ + super().__init__(**kwargs) + self.service_endpoint = service_endpoint + self.share_name = share_name + self.share_snapshot = share_snapshot + self.encoded = encoded + self.directory_path = directory_path + self.prefix = prefix + self.marker = marker + self.max_results = max_results + self.segment = segment + self.next_marker = next_marker + self.directory_id = directory_id + + +class ListHandlesResponse(_serialization.Model): + """An enumeration of handles. + + All required parameters must be populated in order to send to server. + + :ivar handle_list: + :vartype handle_list: list[~azure.storage.fileshare.models.HandleItem] + :ivar next_marker: Required. + :vartype next_marker: str + """ + + _validation = { + "next_marker": {"required": True}, + } + + _attribute_map = { + "handle_list": { + "key": "HandleList", + "type": "[HandleItem]", + "xml": {"name": "Entries", "wrapped": True, "itemsName": "Handle"}, + }, + "next_marker": {"key": "NextMarker", "type": "str"}, + } + _xml_map = {"name": "EnumerationResults"} + + def __init__( + self, *, next_marker: str, handle_list: Optional[List["_models.HandleItem"]] = None, **kwargs: Any + ) -> None: + """ + :keyword handle_list: + :paramtype handle_list: list[~azure.storage.fileshare.models.HandleItem] + :keyword next_marker: Required. + :paramtype next_marker: str + """ + super().__init__(**kwargs) + self.handle_list = handle_list + self.next_marker = next_marker + + +class ListSharesResponse(_serialization.Model): + """An enumeration of shares. + + All required parameters must be populated in order to send to server. + + :ivar service_endpoint: Required. + :vartype service_endpoint: str + :ivar prefix: + :vartype prefix: str + :ivar marker: + :vartype marker: str + :ivar max_results: + :vartype max_results: int + :ivar share_items: + :vartype share_items: list[~azure.storage.fileshare.models.ShareItemInternal] + :ivar next_marker: Required. + :vartype next_marker: str + """ + + _validation = { + "service_endpoint": {"required": True}, + "next_marker": {"required": True}, + } + + _attribute_map = { + "service_endpoint": {"key": "ServiceEndpoint", "type": "str", "xml": {"attr": True}}, + "prefix": {"key": "Prefix", "type": "str"}, + "marker": {"key": "Marker", "type": "str"}, + "max_results": {"key": "MaxResults", "type": "int"}, + "share_items": { + "key": "ShareItems", + "type": "[ShareItemInternal]", + "xml": {"name": "Shares", "wrapped": True, "itemsName": "Share"}, + }, + "next_marker": {"key": "NextMarker", "type": "str"}, + } + _xml_map = {"name": "EnumerationResults"} + + def __init__( + self, + *, + service_endpoint: str, + next_marker: str, + prefix: Optional[str] = None, + marker: Optional[str] = None, + max_results: Optional[int] = None, + share_items: Optional[List["_models.ShareItemInternal"]] = None, + **kwargs: Any + ) -> None: + """ + :keyword service_endpoint: Required. + :paramtype service_endpoint: str + :keyword prefix: + :paramtype prefix: str + :keyword marker: + :paramtype marker: str + :keyword max_results: + :paramtype max_results: int + :keyword share_items: + :paramtype share_items: list[~azure.storage.fileshare.models.ShareItemInternal] + :keyword next_marker: Required. + :paramtype next_marker: str + """ + super().__init__(**kwargs) + self.service_endpoint = service_endpoint + self.prefix = prefix + self.marker = marker + self.max_results = max_results + self.share_items = share_items + self.next_marker = next_marker + + +class Metrics(_serialization.Model): + """Storage Analytics metrics for file service. + + All required parameters must be populated in order to send to server. + + :ivar version: The version of Storage Analytics to configure. Required. + :vartype version: str + :ivar enabled: Indicates whether metrics are enabled for the File service. Required. + :vartype enabled: bool + :ivar include_apis: Indicates whether metrics should generate summary statistics for called API + operations. + :vartype include_apis: bool + :ivar retention_policy: The retention policy. + :vartype retention_policy: ~azure.storage.fileshare.models.RetentionPolicy + """ + + _validation = { + "version": {"required": True}, + "enabled": {"required": True}, + } + + _attribute_map = { + "version": {"key": "Version", "type": "str"}, + "enabled": {"key": "Enabled", "type": "bool"}, + "include_apis": {"key": "IncludeAPIs", "type": "bool"}, + "retention_policy": {"key": "RetentionPolicy", "type": "RetentionPolicy"}, + } + + def __init__( + self, + *, + version: str, + enabled: bool, + include_apis: Optional[bool] = None, + retention_policy: Optional["_models.RetentionPolicy"] = None, + **kwargs: Any + ) -> None: + """ + :keyword version: The version of Storage Analytics to configure. Required. + :paramtype version: str + :keyword enabled: Indicates whether metrics are enabled for the File service. Required. + :paramtype enabled: bool + :keyword include_apis: Indicates whether metrics should generate summary statistics for called + API operations. + :paramtype include_apis: bool + :keyword retention_policy: The retention policy. + :paramtype retention_policy: ~azure.storage.fileshare.models.RetentionPolicy + """ + super().__init__(**kwargs) + self.version = version + self.enabled = enabled + self.include_apis = include_apis + self.retention_policy = retention_policy + + +class RetentionPolicy(_serialization.Model): + """The retention policy. + + All required parameters must be populated in order to send to server. + + :ivar enabled: Indicates whether a retention policy is enabled for the File service. If false, + metrics data is retained, and the user is responsible for deleting it. Required. + :vartype enabled: bool + :ivar days: Indicates the number of days that metrics data should be retained. All data older + than this value will be deleted. Metrics data is deleted on a best-effort basis after the + retention period expires. + :vartype days: int + """ + + _validation = { + "enabled": {"required": True}, + "days": {"maximum": 365, "minimum": 1}, + } + + _attribute_map = { + "enabled": {"key": "Enabled", "type": "bool"}, + "days": {"key": "Days", "type": "int"}, + } + + def __init__(self, *, enabled: bool, days: Optional[int] = None, **kwargs: Any) -> None: + """ + :keyword enabled: Indicates whether a retention policy is enabled for the File service. If + false, metrics data is retained, and the user is responsible for deleting it. Required. + :paramtype enabled: bool + :keyword days: Indicates the number of days that metrics data should be retained. All data + older than this value will be deleted. Metrics data is deleted on a best-effort basis after the + retention period expires. + :paramtype days: int + """ + super().__init__(**kwargs) + self.enabled = enabled + self.days = days + + +class ShareFileRangeList(_serialization.Model): + """The list of file ranges. + + :ivar ranges: + :vartype ranges: list[~azure.storage.fileshare.models.FileRange] + :ivar clear_ranges: + :vartype clear_ranges: list[~azure.storage.fileshare.models.ClearRange] + """ + + _attribute_map = { + "ranges": {"key": "Ranges", "type": "[FileRange]", "xml": {"itemsName": "Range"}}, + "clear_ranges": {"key": "ClearRanges", "type": "[ClearRange]", "xml": {"itemsName": "ClearRange"}}, + } + + def __init__( + self, + *, + ranges: Optional[List["_models.FileRange"]] = None, + clear_ranges: Optional[List["_models.ClearRange"]] = None, + **kwargs: Any + ) -> None: + """ + :keyword ranges: + :paramtype ranges: list[~azure.storage.fileshare.models.FileRange] + :keyword clear_ranges: + :paramtype clear_ranges: list[~azure.storage.fileshare.models.ClearRange] + """ + super().__init__(**kwargs) + self.ranges = ranges + self.clear_ranges = clear_ranges + + +class ShareItemInternal(_serialization.Model): + """A listed Azure Storage share item. + + All required parameters must be populated in order to send to server. + + :ivar name: Required. + :vartype name: str + :ivar snapshot: + :vartype snapshot: str + :ivar deleted: + :vartype deleted: bool + :ivar version: + :vartype version: str + :ivar properties: Properties of a share. Required. + :vartype properties: ~azure.storage.fileshare.models.SharePropertiesInternal + :ivar metadata: Dictionary of :code:`<string>`. + :vartype metadata: dict[str, str] + """ + + _validation = { + "name": {"required": True}, + "properties": {"required": True}, + } + + _attribute_map = { + "name": {"key": "Name", "type": "str"}, + "snapshot": {"key": "Snapshot", "type": "str"}, + "deleted": {"key": "Deleted", "type": "bool"}, + "version": {"key": "Version", "type": "str"}, + "properties": {"key": "Properties", "type": "SharePropertiesInternal"}, + "metadata": {"key": "Metadata", "type": "{str}"}, + } + _xml_map = {"name": "Share"} + + def __init__( + self, + *, + name: str, + properties: "_models.SharePropertiesInternal", + snapshot: Optional[str] = None, + deleted: Optional[bool] = None, + version: Optional[str] = None, + metadata: Optional[Dict[str, str]] = None, + **kwargs: Any + ) -> None: + """ + :keyword name: Required. + :paramtype name: str + :keyword snapshot: + :paramtype snapshot: str + :keyword deleted: + :paramtype deleted: bool + :keyword version: + :paramtype version: str + :keyword properties: Properties of a share. Required. + :paramtype properties: ~azure.storage.fileshare.models.SharePropertiesInternal + :keyword metadata: Dictionary of :code:`<string>`. + :paramtype metadata: dict[str, str] + """ + super().__init__(**kwargs) + self.name = name + self.snapshot = snapshot + self.deleted = deleted + self.version = version + self.properties = properties + self.metadata = metadata + + +class SharePermission(_serialization.Model): + """A permission (a security descriptor) at the share level. + + All required parameters must be populated in order to send to server. + + :ivar permission: The permission in the Security Descriptor Definition Language (SDDL). + Required. + :vartype permission: str + :ivar format: Known values are: "Sddl" and "Binary". + :vartype format: str or ~azure.storage.fileshare.models.FilePermissionFormat + """ + + _validation = { + "permission": {"required": True}, + } + + _attribute_map = { + "permission": {"key": "permission", "type": "str"}, + "format": {"key": "format", "type": "str"}, + } + + def __init__( + self, *, permission: str, format: Optional[Union[str, "_models.FilePermissionFormat"]] = None, **kwargs: Any + ) -> None: + """ + :keyword permission: The permission in the Security Descriptor Definition Language (SDDL). + Required. + :paramtype permission: str + :keyword format: Known values are: "Sddl" and "Binary". + :paramtype format: str or ~azure.storage.fileshare.models.FilePermissionFormat + """ + super().__init__(**kwargs) + self.permission = permission + self.format = format + + +class SharePropertiesInternal(_serialization.Model): + """Properties of a share. + + All required parameters must be populated in order to send to server. + + :ivar last_modified: Required. + :vartype last_modified: ~datetime.datetime + :ivar etag: Required. + :vartype etag: str + :ivar quota: Required. + :vartype quota: int + :ivar provisioned_iops: + :vartype provisioned_iops: int + :ivar provisioned_ingress_m_bps: + :vartype provisioned_ingress_m_bps: int + :ivar provisioned_egress_m_bps: + :vartype provisioned_egress_m_bps: int + :ivar provisioned_bandwidth_mi_bps: + :vartype provisioned_bandwidth_mi_bps: int + :ivar next_allowed_quota_downgrade_time: + :vartype next_allowed_quota_downgrade_time: ~datetime.datetime + :ivar deleted_time: + :vartype deleted_time: ~datetime.datetime + :ivar remaining_retention_days: + :vartype remaining_retention_days: int + :ivar access_tier: + :vartype access_tier: str + :ivar access_tier_change_time: + :vartype access_tier_change_time: ~datetime.datetime + :ivar access_tier_transition_state: + :vartype access_tier_transition_state: str + :ivar lease_status: The current lease status of the share. Known values are: "locked" and + "unlocked". + :vartype lease_status: str or ~azure.storage.fileshare.models.LeaseStatusType + :ivar lease_state: Lease state of the share. Known values are: "available", "leased", + "expired", "breaking", and "broken". + :vartype lease_state: str or ~azure.storage.fileshare.models.LeaseStateType + :ivar lease_duration: When a share is leased, specifies whether the lease is of infinite or + fixed duration. Known values are: "infinite" and "fixed". + :vartype lease_duration: str or ~azure.storage.fileshare.models.LeaseDurationType + :ivar enabled_protocols: + :vartype enabled_protocols: str + :ivar root_squash: Known values are: "NoRootSquash", "RootSquash", and "AllSquash". + :vartype root_squash: str or ~azure.storage.fileshare.models.ShareRootSquash + :ivar enable_snapshot_virtual_directory_access: + :vartype enable_snapshot_virtual_directory_access: bool + :ivar paid_bursting_enabled: + :vartype paid_bursting_enabled: bool + :ivar paid_bursting_max_iops: + :vartype paid_bursting_max_iops: int + :ivar paid_bursting_max_bandwidth_mibps: + :vartype paid_bursting_max_bandwidth_mibps: int + :ivar included_burst_iops: + :vartype included_burst_iops: int + :ivar max_burst_credits_for_iops: + :vartype max_burst_credits_for_iops: int + :ivar next_allowed_provisioned_iops_downgrade_time: + :vartype next_allowed_provisioned_iops_downgrade_time: ~datetime.datetime + :ivar next_allowed_provisioned_bandwidth_downgrade_time: + :vartype next_allowed_provisioned_bandwidth_downgrade_time: ~datetime.datetime + """ + + _validation = { + "last_modified": {"required": True}, + "etag": {"required": True}, + "quota": {"required": True}, + } + + _attribute_map = { + "last_modified": {"key": "Last-Modified", "type": "rfc-1123"}, + "etag": {"key": "Etag", "type": "str"}, + "quota": {"key": "Quota", "type": "int"}, + "provisioned_iops": {"key": "ProvisionedIops", "type": "int"}, + "provisioned_ingress_m_bps": {"key": "ProvisionedIngressMBps", "type": "int"}, + "provisioned_egress_m_bps": {"key": "ProvisionedEgressMBps", "type": "int"}, + "provisioned_bandwidth_mi_bps": {"key": "ProvisionedBandwidthMiBps", "type": "int"}, + "next_allowed_quota_downgrade_time": {"key": "NextAllowedQuotaDowngradeTime", "type": "rfc-1123"}, + "deleted_time": {"key": "DeletedTime", "type": "rfc-1123"}, + "remaining_retention_days": {"key": "RemainingRetentionDays", "type": "int"}, + "access_tier": {"key": "AccessTier", "type": "str"}, + "access_tier_change_time": {"key": "AccessTierChangeTime", "type": "rfc-1123"}, + "access_tier_transition_state": {"key": "AccessTierTransitionState", "type": "str"}, + "lease_status": {"key": "LeaseStatus", "type": "str"}, + "lease_state": {"key": "LeaseState", "type": "str"}, + "lease_duration": {"key": "LeaseDuration", "type": "str"}, + "enabled_protocols": {"key": "EnabledProtocols", "type": "str"}, + "root_squash": {"key": "RootSquash", "type": "str"}, + "enable_snapshot_virtual_directory_access": {"key": "EnableSnapshotVirtualDirectoryAccess", "type": "bool"}, + "paid_bursting_enabled": {"key": "PaidBurstingEnabled", "type": "bool"}, + "paid_bursting_max_iops": {"key": "PaidBurstingMaxIops", "type": "int"}, + "paid_bursting_max_bandwidth_mibps": {"key": "PaidBurstingMaxBandwidthMibps", "type": "int"}, + "included_burst_iops": {"key": "IncludedBurstIops", "type": "int"}, + "max_burst_credits_for_iops": {"key": "MaxBurstCreditsForIops", "type": "int"}, + "next_allowed_provisioned_iops_downgrade_time": { + "key": "NextAllowedProvisionedIopsDowngradeTime", + "type": "rfc-1123", + }, + "next_allowed_provisioned_bandwidth_downgrade_time": { + "key": "NextAllowedProvisionedBandwidthDowngradeTime", + "type": "rfc-1123", + }, + } + + def __init__( # pylint: disable=too-many-locals + self, + *, + last_modified: datetime.datetime, + etag: str, + quota: int, + provisioned_iops: Optional[int] = None, + provisioned_ingress_m_bps: Optional[int] = None, + provisioned_egress_m_bps: Optional[int] = None, + provisioned_bandwidth_mi_bps: Optional[int] = None, + next_allowed_quota_downgrade_time: Optional[datetime.datetime] = None, + deleted_time: Optional[datetime.datetime] = None, + remaining_retention_days: Optional[int] = None, + access_tier: Optional[str] = None, + access_tier_change_time: Optional[datetime.datetime] = None, + access_tier_transition_state: Optional[str] = None, + lease_status: Optional[Union[str, "_models.LeaseStatusType"]] = None, + lease_state: Optional[Union[str, "_models.LeaseStateType"]] = None, + lease_duration: Optional[Union[str, "_models.LeaseDurationType"]] = None, + enabled_protocols: Optional[str] = None, + root_squash: Optional[Union[str, "_models.ShareRootSquash"]] = None, + enable_snapshot_virtual_directory_access: Optional[bool] = None, + paid_bursting_enabled: Optional[bool] = None, + paid_bursting_max_iops: Optional[int] = None, + paid_bursting_max_bandwidth_mibps: Optional[int] = None, + included_burst_iops: Optional[int] = None, + max_burst_credits_for_iops: Optional[int] = None, + next_allowed_provisioned_iops_downgrade_time: Optional[datetime.datetime] = None, + next_allowed_provisioned_bandwidth_downgrade_time: Optional[datetime.datetime] = None, + **kwargs: Any + ) -> None: + """ + :keyword last_modified: Required. + :paramtype last_modified: ~datetime.datetime + :keyword etag: Required. + :paramtype etag: str + :keyword quota: Required. + :paramtype quota: int + :keyword provisioned_iops: + :paramtype provisioned_iops: int + :keyword provisioned_ingress_m_bps: + :paramtype provisioned_ingress_m_bps: int + :keyword provisioned_egress_m_bps: + :paramtype provisioned_egress_m_bps: int + :keyword provisioned_bandwidth_mi_bps: + :paramtype provisioned_bandwidth_mi_bps: int + :keyword next_allowed_quota_downgrade_time: + :paramtype next_allowed_quota_downgrade_time: ~datetime.datetime + :keyword deleted_time: + :paramtype deleted_time: ~datetime.datetime + :keyword remaining_retention_days: + :paramtype remaining_retention_days: int + :keyword access_tier: + :paramtype access_tier: str + :keyword access_tier_change_time: + :paramtype access_tier_change_time: ~datetime.datetime + :keyword access_tier_transition_state: + :paramtype access_tier_transition_state: str + :keyword lease_status: The current lease status of the share. Known values are: "locked" and + "unlocked". + :paramtype lease_status: str or ~azure.storage.fileshare.models.LeaseStatusType + :keyword lease_state: Lease state of the share. Known values are: "available", "leased", + "expired", "breaking", and "broken". + :paramtype lease_state: str or ~azure.storage.fileshare.models.LeaseStateType + :keyword lease_duration: When a share is leased, specifies whether the lease is of infinite or + fixed duration. Known values are: "infinite" and "fixed". + :paramtype lease_duration: str or ~azure.storage.fileshare.models.LeaseDurationType + :keyword enabled_protocols: + :paramtype enabled_protocols: str + :keyword root_squash: Known values are: "NoRootSquash", "RootSquash", and "AllSquash". + :paramtype root_squash: str or ~azure.storage.fileshare.models.ShareRootSquash + :keyword enable_snapshot_virtual_directory_access: + :paramtype enable_snapshot_virtual_directory_access: bool + :keyword paid_bursting_enabled: + :paramtype paid_bursting_enabled: bool + :keyword paid_bursting_max_iops: + :paramtype paid_bursting_max_iops: int + :keyword paid_bursting_max_bandwidth_mibps: + :paramtype paid_bursting_max_bandwidth_mibps: int + :keyword included_burst_iops: + :paramtype included_burst_iops: int + :keyword max_burst_credits_for_iops: + :paramtype max_burst_credits_for_iops: int + :keyword next_allowed_provisioned_iops_downgrade_time: + :paramtype next_allowed_provisioned_iops_downgrade_time: ~datetime.datetime + :keyword next_allowed_provisioned_bandwidth_downgrade_time: + :paramtype next_allowed_provisioned_bandwidth_downgrade_time: ~datetime.datetime + """ + super().__init__(**kwargs) + self.last_modified = last_modified + self.etag = etag + self.quota = quota + self.provisioned_iops = provisioned_iops + self.provisioned_ingress_m_bps = provisioned_ingress_m_bps + self.provisioned_egress_m_bps = provisioned_egress_m_bps + self.provisioned_bandwidth_mi_bps = provisioned_bandwidth_mi_bps + self.next_allowed_quota_downgrade_time = next_allowed_quota_downgrade_time + self.deleted_time = deleted_time + self.remaining_retention_days = remaining_retention_days + self.access_tier = access_tier + self.access_tier_change_time = access_tier_change_time + self.access_tier_transition_state = access_tier_transition_state + self.lease_status = lease_status + self.lease_state = lease_state + self.lease_duration = lease_duration + self.enabled_protocols = enabled_protocols + self.root_squash = root_squash + self.enable_snapshot_virtual_directory_access = enable_snapshot_virtual_directory_access + self.paid_bursting_enabled = paid_bursting_enabled + self.paid_bursting_max_iops = paid_bursting_max_iops + self.paid_bursting_max_bandwidth_mibps = paid_bursting_max_bandwidth_mibps + self.included_burst_iops = included_burst_iops + self.max_burst_credits_for_iops = max_burst_credits_for_iops + self.next_allowed_provisioned_iops_downgrade_time = next_allowed_provisioned_iops_downgrade_time + self.next_allowed_provisioned_bandwidth_downgrade_time = next_allowed_provisioned_bandwidth_downgrade_time + + +class ShareProtocolSettings(_serialization.Model): + """Protocol settings. + + :ivar smb: Settings for SMB protocol. + :vartype smb: ~azure.storage.fileshare.models.ShareSmbSettings + """ + + _attribute_map = { + "smb": {"key": "Smb", "type": "ShareSmbSettings"}, + } + _xml_map = {"name": "ProtocolSettings"} + + def __init__(self, *, smb: Optional["_models.ShareSmbSettings"] = None, **kwargs: Any) -> None: + """ + :keyword smb: Settings for SMB protocol. + :paramtype smb: ~azure.storage.fileshare.models.ShareSmbSettings + """ + super().__init__(**kwargs) + self.smb = smb + + +class ShareSmbSettings(_serialization.Model): + """Settings for SMB protocol. + + :ivar multichannel: Settings for SMB Multichannel. + :vartype multichannel: ~azure.storage.fileshare.models.SmbMultichannel + """ + + _attribute_map = { + "multichannel": {"key": "Multichannel", "type": "SmbMultichannel"}, + } + _xml_map = {"name": "SMB"} + + def __init__(self, *, multichannel: Optional["_models.SmbMultichannel"] = None, **kwargs: Any) -> None: + """ + :keyword multichannel: Settings for SMB Multichannel. + :paramtype multichannel: ~azure.storage.fileshare.models.SmbMultichannel + """ + super().__init__(**kwargs) + self.multichannel = multichannel + + +class ShareStats(_serialization.Model): + """Stats for the share. + + All required parameters must be populated in order to send to server. + + :ivar share_usage_bytes: The approximate size of the data stored in bytes. Note that this value + may not include all recently created or recently resized files. Required. + :vartype share_usage_bytes: int + """ + + _validation = { + "share_usage_bytes": {"required": True}, + } + + _attribute_map = { + "share_usage_bytes": {"key": "ShareUsageBytes", "type": "int"}, + } + + def __init__(self, *, share_usage_bytes: int, **kwargs: Any) -> None: + """ + :keyword share_usage_bytes: The approximate size of the data stored in bytes. Note that this + value may not include all recently created or recently resized files. Required. + :paramtype share_usage_bytes: int + """ + super().__init__(**kwargs) + self.share_usage_bytes = share_usage_bytes + + +class SignedIdentifier(_serialization.Model): + """Signed identifier. + + All required parameters must be populated in order to send to server. + + :ivar id: A unique id. Required. + :vartype id: str + :ivar access_policy: The access policy. + :vartype access_policy: ~azure.storage.fileshare.models.AccessPolicy + """ + + _validation = { + "id": {"required": True}, + } + + _attribute_map = { + "id": {"key": "Id", "type": "str"}, + "access_policy": {"key": "AccessPolicy", "type": "AccessPolicy"}, + } + + def __init__( + self, + *, + id: str, # pylint: disable=redefined-builtin + access_policy: Optional["_models.AccessPolicy"] = None, + **kwargs: Any + ) -> None: + """ + :keyword id: A unique id. Required. + :paramtype id: str + :keyword access_policy: The access policy. + :paramtype access_policy: ~azure.storage.fileshare.models.AccessPolicy + """ + super().__init__(**kwargs) + self.id = id + self.access_policy = access_policy + + +class SmbMultichannel(_serialization.Model): + """Settings for SMB multichannel. + + :ivar enabled: If SMB multichannel is enabled. + :vartype enabled: bool + """ + + _attribute_map = { + "enabled": {"key": "Enabled", "type": "bool"}, + } + _xml_map = {"name": "Multichannel"} + + def __init__(self, *, enabled: Optional[bool] = None, **kwargs: Any) -> None: + """ + :keyword enabled: If SMB multichannel is enabled. + :paramtype enabled: bool + """ + super().__init__(**kwargs) + self.enabled = enabled + + +class SourceLeaseAccessConditions(_serialization.Model): + """Parameter group. + + :ivar source_lease_id: Required if the source file has an active infinite lease. + :vartype source_lease_id: str + """ + + _attribute_map = { + "source_lease_id": {"key": "sourceLeaseId", "type": "str"}, + } + + def __init__(self, *, source_lease_id: Optional[str] = None, **kwargs: Any) -> None: + """ + :keyword source_lease_id: Required if the source file has an active infinite lease. + :paramtype source_lease_id: str + """ + super().__init__(**kwargs) + self.source_lease_id = source_lease_id + + +class SourceModifiedAccessConditions(_serialization.Model): + """Parameter group. + + :ivar source_if_match_crc64: Specify the crc64 value to operate only on range with a matching + crc64 checksum. + :vartype source_if_match_crc64: bytes + :ivar source_if_none_match_crc64: Specify the crc64 value to operate only on range without a + matching crc64 checksum. + :vartype source_if_none_match_crc64: bytes + """ + + _attribute_map = { + "source_if_match_crc64": {"key": "sourceIfMatchCrc64", "type": "bytearray"}, + "source_if_none_match_crc64": {"key": "sourceIfNoneMatchCrc64", "type": "bytearray"}, + } + + def __init__( + self, + *, + source_if_match_crc64: Optional[bytes] = None, + source_if_none_match_crc64: Optional[bytes] = None, + **kwargs: Any + ) -> None: + """ + :keyword source_if_match_crc64: Specify the crc64 value to operate only on range with a + matching crc64 checksum. + :paramtype source_if_match_crc64: bytes + :keyword source_if_none_match_crc64: Specify the crc64 value to operate only on range without a + matching crc64 checksum. + :paramtype source_if_none_match_crc64: bytes + """ + super().__init__(**kwargs) + self.source_if_match_crc64 = source_if_match_crc64 + self.source_if_none_match_crc64 = source_if_none_match_crc64 + + +class StorageError(_serialization.Model): + """StorageError. + + :ivar message: + :vartype message: str + :ivar authentication_error_detail: + :vartype authentication_error_detail: str + """ + + _attribute_map = { + "message": {"key": "Message", "type": "str"}, + "authentication_error_detail": {"key": "AuthenticationErrorDetail", "type": "str"}, + } + + def __init__( + self, *, message: Optional[str] = None, authentication_error_detail: Optional[str] = None, **kwargs: Any + ) -> None: + """ + :keyword message: + :paramtype message: str + :keyword authentication_error_detail: + :paramtype authentication_error_detail: str + """ + super().__init__(**kwargs) + self.message = message + self.authentication_error_detail = authentication_error_detail + + +class StorageServiceProperties(_serialization.Model): + """Storage service properties. + + :ivar hour_metrics: A summary of request statistics grouped by API in hourly aggregates for + files. + :vartype hour_metrics: ~azure.storage.fileshare.models.Metrics + :ivar minute_metrics: A summary of request statistics grouped by API in minute aggregates for + files. + :vartype minute_metrics: ~azure.storage.fileshare.models.Metrics + :ivar cors: The set of CORS rules. + :vartype cors: list[~azure.storage.fileshare.models.CorsRule] + :ivar protocol: Protocol settings. + :vartype protocol: ~azure.storage.fileshare.models.ShareProtocolSettings + """ + + _attribute_map = { + "hour_metrics": {"key": "HourMetrics", "type": "Metrics"}, + "minute_metrics": {"key": "MinuteMetrics", "type": "Metrics"}, + "cors": {"key": "Cors", "type": "[CorsRule]", "xml": {"wrapped": True}}, + "protocol": {"key": "Protocol", "type": "ShareProtocolSettings"}, + } + + def __init__( + self, + *, + hour_metrics: Optional["_models.Metrics"] = None, + minute_metrics: Optional["_models.Metrics"] = None, + cors: Optional[List["_models.CorsRule"]] = None, + protocol: Optional["_models.ShareProtocolSettings"] = None, + **kwargs: Any + ) -> None: + """ + :keyword hour_metrics: A summary of request statistics grouped by API in hourly aggregates for + files. + :paramtype hour_metrics: ~azure.storage.fileshare.models.Metrics + :keyword minute_metrics: A summary of request statistics grouped by API in minute aggregates + for files. + :paramtype minute_metrics: ~azure.storage.fileshare.models.Metrics + :keyword cors: The set of CORS rules. + :paramtype cors: list[~azure.storage.fileshare.models.CorsRule] + :keyword protocol: Protocol settings. + :paramtype protocol: ~azure.storage.fileshare.models.ShareProtocolSettings + """ + super().__init__(**kwargs) + self.hour_metrics = hour_metrics + self.minute_metrics = minute_metrics + self.cors = cors + self.protocol = protocol + + +class StringEncoded(_serialization.Model): + """StringEncoded. + + :ivar encoded: + :vartype encoded: bool + :ivar content: + :vartype content: str + """ + + _attribute_map = { + "encoded": {"key": "Encoded", "type": "bool", "xml": {"name": "Encoded", "attr": True}}, + "content": {"key": "content", "type": "str", "xml": {"text": True}}, + } + + def __init__(self, *, encoded: Optional[bool] = None, content: Optional[str] = None, **kwargs: Any) -> None: + """ + :keyword encoded: + :paramtype encoded: bool + :keyword content: + :paramtype content: str + """ + super().__init__(**kwargs) + self.encoded = encoded + self.content = content diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/models/_patch.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/models/_patch.py new file mode 100644 index 00000000..f7dd3251 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/models/_patch.py @@ -0,0 +1,20 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Customize generated code here. + +Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize +""" +from typing import List + +__all__: List[str] = [] # Add all objects you want publicly available to users at this package level + + +def patch_sdk(): + """Do not remove from this file. + + `patch_sdk` is a last resort escape hatch that allows you to do customizations + you can't accomplish using the techniques described in + https://aka.ms/azsdk/python/dpcodegen/python/customize + """ diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/__init__.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/__init__.py new file mode 100644 index 00000000..092b7efd --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/__init__.py @@ -0,0 +1,31 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +# pylint: disable=wrong-import-position + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from ._patch import * # pylint: disable=unused-wildcard-import + +from ._service_operations import ServiceOperations # type: ignore +from ._share_operations import ShareOperations # type: ignore +from ._directory_operations import DirectoryOperations # type: ignore +from ._file_operations import FileOperations # type: ignore + +from ._patch import __all__ as _patch_all +from ._patch import * +from ._patch import patch_sdk as _patch_sdk + +__all__ = [ + "ServiceOperations", + "ShareOperations", + "DirectoryOperations", + "FileOperations", +] +__all__.extend([p for p in _patch_all if p not in __all__]) # pyright: ignore +_patch_sdk() diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_directory_operations.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_directory_operations.py new file mode 100644 index 00000000..18e4eabd --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_directory_operations.py @@ -0,0 +1,1570 @@ +# pylint: disable=too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +import sys +from typing import Any, Callable, Dict, List, Literal, Optional, TypeVar, Union + +from azure.core import PipelineClient +from azure.core.exceptions import ( + ClientAuthenticationError, + HttpResponseError, + ResourceExistsError, + ResourceNotFoundError, + ResourceNotModifiedError, + map_error, +) +from azure.core.pipeline import PipelineResponse +from azure.core.rest import HttpRequest, HttpResponse +from azure.core.tracing.decorator import distributed_trace +from azure.core.utils import case_insensitive_dict + +from .. import models as _models +from .._configuration import AzureFileStorageConfiguration +from .._serialization import Deserializer, Serializer + +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore +T = TypeVar("T") +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +_SERIALIZER = Serializer() +_SERIALIZER.client_side_validation = False + + +def build_create_request( + url: str, + *, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + file_attributes: str = "none", + file_creation_time: str = "now", + file_last_write_time: str = "now", + file_change_time: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if metadata is not None: + _headers["x-ms-meta"] = _SERIALIZER.header("metadata", metadata, "{str}") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if file_permission is not None: + _headers["x-ms-file-permission"] = _SERIALIZER.header("file_permission", file_permission, "str") + if file_permission_format is not None: + _headers["x-ms-file-permission-format"] = _SERIALIZER.header( + "file_permission_format", file_permission_format, "str" + ) + if file_permission_key is not None: + _headers["x-ms-file-permission-key"] = _SERIALIZER.header("file_permission_key", file_permission_key, "str") + if file_attributes is not None: + _headers["x-ms-file-attributes"] = _SERIALIZER.header("file_attributes", file_attributes, "str") + if file_creation_time is not None: + _headers["x-ms-file-creation-time"] = _SERIALIZER.header("file_creation_time", file_creation_time, "str") + if file_last_write_time is not None: + _headers["x-ms-file-last-write-time"] = _SERIALIZER.header("file_last_write_time", file_last_write_time, "str") + if file_change_time is not None: + _headers["x-ms-file-change-time"] = _SERIALIZER.header("file_change_time", file_change_time, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + if owner is not None: + _headers["x-ms-owner"] = _SERIALIZER.header("owner", owner, "str") + if group is not None: + _headers["x-ms-group"] = _SERIALIZER.header("group", group, "str") + if file_mode is not None: + _headers["x-ms-mode"] = _SERIALIZER.header("file_mode", file_mode, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_get_properties_request( + url: str, + *, + sharesnapshot: Optional[str] = None, + timeout: Optional[int] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_delete_request( + url: str, + *, + timeout: Optional[int] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_set_properties_request( + url: str, + *, + timeout: Optional[int] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + file_attributes: str = "none", + file_creation_time: str = "now", + file_last_write_time: str = "now", + file_change_time: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if file_permission is not None: + _headers["x-ms-file-permission"] = _SERIALIZER.header("file_permission", file_permission, "str") + if file_permission_format is not None: + _headers["x-ms-file-permission-format"] = _SERIALIZER.header( + "file_permission_format", file_permission_format, "str" + ) + if file_permission_key is not None: + _headers["x-ms-file-permission-key"] = _SERIALIZER.header("file_permission_key", file_permission_key, "str") + if file_attributes is not None: + _headers["x-ms-file-attributes"] = _SERIALIZER.header("file_attributes", file_attributes, "str") + if file_creation_time is not None: + _headers["x-ms-file-creation-time"] = _SERIALIZER.header("file_creation_time", file_creation_time, "str") + if file_last_write_time is not None: + _headers["x-ms-file-last-write-time"] = _SERIALIZER.header("file_last_write_time", file_last_write_time, "str") + if file_change_time is not None: + _headers["x-ms-file-change-time"] = _SERIALIZER.header("file_change_time", file_change_time, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + if owner is not None: + _headers["x-ms-owner"] = _SERIALIZER.header("owner", owner, "str") + if group is not None: + _headers["x-ms-group"] = _SERIALIZER.header("group", group, "str") + if file_mode is not None: + _headers["x-ms-mode"] = _SERIALIZER.header("file_mode", file_mode, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_set_metadata_request( + url: str, + *, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + comp: Literal["metadata"] = kwargs.pop("comp", _params.pop("comp", "metadata")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + if metadata is not None: + _headers["x-ms-meta"] = _SERIALIZER.header("metadata", metadata, "{str}") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_list_files_and_directories_segment_request( # pylint: disable=name-too-long + url: str, + *, + prefix: Optional[str] = None, + sharesnapshot: Optional[str] = None, + marker: Optional[str] = None, + maxresults: Optional[int] = None, + timeout: Optional[int] = None, + include: Optional[List[Union[str, _models.ListFilesIncludeType]]] = None, + include_extended_info: Optional[bool] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + comp: Literal["list"] = kwargs.pop("comp", _params.pop("comp", "list")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if prefix is not None: + _params["prefix"] = _SERIALIZER.query("prefix", prefix, "str") + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + if marker is not None: + _params["marker"] = _SERIALIZER.query("marker", marker, "str") + if maxresults is not None: + _params["maxresults"] = _SERIALIZER.query("maxresults", maxresults, "int", minimum=1) + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + if include is not None: + _params["include"] = _SERIALIZER.query("include", include, "[str]", div=",") + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if include_extended_info is not None: + _headers["x-ms-file-extended-info"] = _SERIALIZER.header("include_extended_info", include_extended_info, "bool") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_list_handles_request( + url: str, + *, + marker: Optional[str] = None, + maxresults: Optional[int] = None, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + recursive: Optional[bool] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["listhandles"] = kwargs.pop("comp", _params.pop("comp", "listhandles")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if marker is not None: + _params["marker"] = _SERIALIZER.query("marker", marker, "str") + if maxresults is not None: + _params["maxresults"] = _SERIALIZER.query("maxresults", maxresults, "int", minimum=1) + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + + # Construct headers + if recursive is not None: + _headers["x-ms-recursive"] = _SERIALIZER.header("recursive", recursive, "bool") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_force_close_handles_request( + url: str, + *, + handle_id: str, + timeout: Optional[int] = None, + marker: Optional[str] = None, + sharesnapshot: Optional[str] = None, + recursive: Optional[bool] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["forceclosehandles"] = kwargs.pop("comp", _params.pop("comp", "forceclosehandles")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + if marker is not None: + _params["marker"] = _SERIALIZER.query("marker", marker, "str") + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + + # Construct headers + _headers["x-ms-handle-id"] = _SERIALIZER.header("handle_id", handle_id, "str") + if recursive is not None: + _headers["x-ms-recursive"] = _SERIALIZER.header("recursive", recursive, "bool") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_rename_request( + url: str, + *, + rename_source: str, + timeout: Optional[int] = None, + replace_if_exists: Optional[bool] = None, + ignore_read_only: Optional[bool] = None, + source_lease_id: Optional[str] = None, + destination_lease_id: Optional[str] = None, + file_attributes: Optional[str] = None, + file_creation_time: Optional[str] = None, + file_last_write_time: Optional[str] = None, + file_change_time: Optional[str] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + metadata: Optional[Dict[str, str]] = None, + allow_trailing_dot: Optional[bool] = None, + allow_source_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + comp: Literal["rename"] = kwargs.pop("comp", _params.pop("comp", "rename")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + _headers["x-ms-file-rename-source"] = _SERIALIZER.header("rename_source", rename_source, "str") + if replace_if_exists is not None: + _headers["x-ms-file-rename-replace-if-exists"] = _SERIALIZER.header( + "replace_if_exists", replace_if_exists, "bool" + ) + if ignore_read_only is not None: + _headers["x-ms-file-rename-ignore-readonly"] = _SERIALIZER.header("ignore_read_only", ignore_read_only, "bool") + if source_lease_id is not None: + _headers["x-ms-source-lease-id"] = _SERIALIZER.header("source_lease_id", source_lease_id, "str") + if destination_lease_id is not None: + _headers["x-ms-destination-lease-id"] = _SERIALIZER.header("destination_lease_id", destination_lease_id, "str") + if file_attributes is not None: + _headers["x-ms-file-attributes"] = _SERIALIZER.header("file_attributes", file_attributes, "str") + if file_creation_time is not None: + _headers["x-ms-file-creation-time"] = _SERIALIZER.header("file_creation_time", file_creation_time, "str") + if file_last_write_time is not None: + _headers["x-ms-file-last-write-time"] = _SERIALIZER.header("file_last_write_time", file_last_write_time, "str") + if file_change_time is not None: + _headers["x-ms-file-change-time"] = _SERIALIZER.header("file_change_time", file_change_time, "str") + if file_permission is not None: + _headers["x-ms-file-permission"] = _SERIALIZER.header("file_permission", file_permission, "str") + if file_permission_format is not None: + _headers["x-ms-file-permission-format"] = _SERIALIZER.header( + "file_permission_format", file_permission_format, "str" + ) + if file_permission_key is not None: + _headers["x-ms-file-permission-key"] = _SERIALIZER.header("file_permission_key", file_permission_key, "str") + if metadata is not None: + _headers["x-ms-meta"] = _SERIALIZER.header("metadata", metadata, "{str}") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if allow_source_trailing_dot is not None: + _headers["x-ms-source-allow-trailing-dot"] = _SERIALIZER.header( + "allow_source_trailing_dot", allow_source_trailing_dot, "bool" + ) + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +class DirectoryOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.storage.fileshare.AzureFileStorage`'s + :attr:`directory` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs): + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AzureFileStorageConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace + def create( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + file_attributes: str = "none", + file_creation_time: str = "now", + file_last_write_time: str = "now", + file_change_time: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Creates a new directory under the specified share or parent directory. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param file_attributes: If specified, the provided file attributes shall be set. Default value: + ‘Archive’ for file and ‘Directory’ for directory. ‘None’ can also be specified as default. + Default value is "none". + :type file_attributes: str + :param file_creation_time: Creation time for the file/directory. Default value: Now. Default + value is "now". + :type file_creation_time: str + :param file_last_write_time: Last write time for the file/directory. Default value: Now. + Default value is "now". + :type file_last_write_time: str + :param file_change_time: Change time for the file/directory. Default value: Now. Default value + is None. + :type file_change_time: str + :param owner: Optional, NFS only. The owner of the file or directory. Default value is None. + :type owner: str + :param group: Optional, NFS only. The owning group of the file or directory. Default value is + None. + :type group: str + :param file_mode: Optional, NFS only. The file mode of the file or directory. Default value is + None. + :type file_mode: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_create_request( + url=self._config.url, + timeout=timeout, + metadata=metadata, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + file_attributes=file_attributes, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + file_change_time=file_change_time, + owner=owner, + group=group, + file_mode=file_mode, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-file-file-type"] = self._deserialize("str", response.headers.get("x-ms-file-file-type")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def get_properties( # pylint: disable=inconsistent-return-statements + self, sharesnapshot: Optional[str] = None, timeout: Optional[int] = None, **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Returns all system properties for the specified directory, and can also be used to check the + existence of a directory. The data returned does not include the files in the directory or any + subdirectories. + + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_get_properties_request( + url=self._config.url, + sharesnapshot=sharesnapshot, + timeout=timeout, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-meta"] = self._deserialize("{str}", response.headers.get("x-ms-meta")) + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-server-encrypted") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-file-file-type"] = self._deserialize("str", response.headers.get("x-ms-file-file-type")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def delete( # pylint: disable=inconsistent-return-statements + self, timeout: Optional[int] = None, **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Removes the specified empty directory. Note that the directory must be empty before it can be + deleted. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_delete_request( + url=self._config.url, + timeout=timeout, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def set_properties( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + file_attributes: str = "none", + file_creation_time: str = "now", + file_last_write_time: str = "now", + file_change_time: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Sets properties on the directory. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param file_attributes: If specified, the provided file attributes shall be set. Default value: + ‘Archive’ for file and ‘Directory’ for directory. ‘None’ can also be specified as default. + Default value is "none". + :type file_attributes: str + :param file_creation_time: Creation time for the file/directory. Default value: Now. Default + value is "now". + :type file_creation_time: str + :param file_last_write_time: Last write time for the file/directory. Default value: Now. + Default value is "now". + :type file_last_write_time: str + :param file_change_time: Change time for the file/directory. Default value: Now. Default value + is None. + :type file_change_time: str + :param owner: Optional, NFS only. The owner of the file or directory. Default value is None. + :type owner: str + :param group: Optional, NFS only. The owning group of the file or directory. Default value is + None. + :type group: str + :param file_mode: Optional, NFS only. The file mode of the file or directory. Default value is + None. + :type file_mode: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_set_properties_request( + url=self._config.url, + timeout=timeout, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + file_attributes=file_attributes, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + file_change_time=file_change_time, + owner=owner, + group=group, + file_mode=file_mode, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def set_metadata( # pylint: disable=inconsistent-return-statements + self, timeout: Optional[int] = None, metadata: Optional[Dict[str, str]] = None, **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Updates user defined metadata for the specified directory. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + comp: Literal["metadata"] = kwargs.pop("comp", _params.pop("comp", "metadata")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_set_metadata_request( + url=self._config.url, + timeout=timeout, + metadata=metadata, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def list_files_and_directories_segment( + self, + prefix: Optional[str] = None, + sharesnapshot: Optional[str] = None, + marker: Optional[str] = None, + maxresults: Optional[int] = None, + timeout: Optional[int] = None, + include: Optional[List[Union[str, _models.ListFilesIncludeType]]] = None, + include_extended_info: Optional[bool] = None, + **kwargs: Any + ) -> _models.ListFilesAndDirectoriesSegmentResponse: + # pylint: disable=line-too-long + """Returns a list of files or directories under the specified share or directory. It lists the + contents only for a single level of the directory hierarchy. + + :param prefix: Filters the results to return only entries whose name begins with the specified + prefix. Default value is None. + :type prefix: str + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param marker: A string value that identifies the portion of the list to be returned with the + next list operation. The operation returns a marker value within the response body if the list + returned was not complete. The marker value may then be used in a subsequent call to request + the next set of list items. The marker value is opaque to the client. Default value is None. + :type marker: str + :param maxresults: Specifies the maximum number of entries to return. If the request does not + specify maxresults, or specifies a value greater than 5,000, the server will return up to 5,000 + items. Default value is None. + :type maxresults: int + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param include: Include this parameter to specify one or more datasets to include in the + response. Default value is None. + :type include: list[str or ~azure.storage.fileshare.models.ListFilesIncludeType] + :param include_extended_info: Include extended information. Default value is None. + :type include_extended_info: bool + :return: ListFilesAndDirectoriesSegmentResponse or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.ListFilesAndDirectoriesSegmentResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + comp: Literal["list"] = kwargs.pop("comp", _params.pop("comp", "list")) + cls: ClsType[_models.ListFilesAndDirectoriesSegmentResponse] = kwargs.pop("cls", None) + + _request = build_list_files_and_directories_segment_request( + url=self._config.url, + prefix=prefix, + sharesnapshot=sharesnapshot, + marker=marker, + maxresults=maxresults, + timeout=timeout, + include=include, + include_extended_info=include_extended_info, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("ListFilesAndDirectoriesSegmentResponse", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list_handles( + self, + marker: Optional[str] = None, + maxresults: Optional[int] = None, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + recursive: Optional[bool] = None, + **kwargs: Any + ) -> _models.ListHandlesResponse: + # pylint: disable=line-too-long + """Lists handles for directory. + + :param marker: A string value that identifies the portion of the list to be returned with the + next list operation. The operation returns a marker value within the response body if the list + returned was not complete. The marker value may then be used in a subsequent call to request + the next set of list items. The marker value is opaque to the client. Default value is None. + :type marker: str + :param maxresults: Specifies the maximum number of entries to return. If the request does not + specify maxresults, or specifies a value greater than 5,000, the server will return up to 5,000 + items. Default value is None. + :type maxresults: int + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param recursive: Specifies operation should apply to the directory specified in the URI, its + files, its subdirectories and their files. Default value is None. + :type recursive: bool + :return: ListHandlesResponse or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.ListHandlesResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["listhandles"] = kwargs.pop("comp", _params.pop("comp", "listhandles")) + cls: ClsType[_models.ListHandlesResponse] = kwargs.pop("cls", None) + + _request = build_list_handles_request( + url=self._config.url, + marker=marker, + maxresults=maxresults, + timeout=timeout, + sharesnapshot=sharesnapshot, + recursive=recursive, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("ListHandlesResponse", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def force_close_handles( # pylint: disable=inconsistent-return-statements + self, + handle_id: str, + timeout: Optional[int] = None, + marker: Optional[str] = None, + sharesnapshot: Optional[str] = None, + recursive: Optional[bool] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Closes all handles open for given directory. + + :param handle_id: Specifies handle ID opened on the file or directory to be closed. Asterisk + (‘*’) is a wildcard that specifies all handles. Required. + :type handle_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param marker: A string value that identifies the portion of the list to be returned with the + next list operation. The operation returns a marker value within the response body if the list + returned was not complete. The marker value may then be used in a subsequent call to request + the next set of list items. The marker value is opaque to the client. Default value is None. + :type marker: str + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param recursive: Specifies operation should apply to the directory specified in the URI, its + files, its subdirectories and their files. Default value is None. + :type recursive: bool + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["forceclosehandles"] = kwargs.pop("comp", _params.pop("comp", "forceclosehandles")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_force_close_handles_request( + url=self._config.url, + handle_id=handle_id, + timeout=timeout, + marker=marker, + sharesnapshot=sharesnapshot, + recursive=recursive, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-marker"] = self._deserialize("str", response.headers.get("x-ms-marker")) + response_headers["x-ms-number-of-handles-closed"] = self._deserialize( + "int", response.headers.get("x-ms-number-of-handles-closed") + ) + response_headers["x-ms-number-of-handles-failed"] = self._deserialize( + "int", response.headers.get("x-ms-number-of-handles-failed") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def rename( # pylint: disable=inconsistent-return-statements + self, + rename_source: str, + timeout: Optional[int] = None, + replace_if_exists: Optional[bool] = None, + ignore_read_only: Optional[bool] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + metadata: Optional[Dict[str, str]] = None, + source_lease_access_conditions: Optional[_models.SourceLeaseAccessConditions] = None, + destination_lease_access_conditions: Optional[_models.DestinationLeaseAccessConditions] = None, + copy_file_smb_info: Optional[_models.CopyFileSmbInfo] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Renames a directory. + + :param rename_source: Required. Specifies the URI-style path of the source file, up to 2 KB in + length. Required. + :type rename_source: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param replace_if_exists: Optional. A boolean value for if the destination file already exists, + whether this request will overwrite the file or not. If true, the rename will succeed and will + overwrite the destination file. If not provided or if false and the destination file does + exist, the request will not overwrite the destination file. If provided and the destination + file doesn’t exist, the rename will succeed. Note: This value does not override the + x-ms-file-copy-ignore-read-only header value. Default value is None. + :type replace_if_exists: bool + :param ignore_read_only: Optional. A boolean value that specifies whether the ReadOnly + attribute on a preexisting destination file should be respected. If true, the rename will + succeed, otherwise, a previous file at the destination with the ReadOnly attribute set will + cause the rename to fail. Default value is None. + :type ignore_read_only: bool + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param source_lease_access_conditions: Parameter group. Default value is None. + :type source_lease_access_conditions: + ~azure.storage.fileshare.models.SourceLeaseAccessConditions + :param destination_lease_access_conditions: Parameter group. Default value is None. + :type destination_lease_access_conditions: + ~azure.storage.fileshare.models.DestinationLeaseAccessConditions + :param copy_file_smb_info: Parameter group. Default value is None. + :type copy_file_smb_info: ~azure.storage.fileshare.models.CopyFileSmbInfo + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["directory"] = kwargs.pop("restype", _params.pop("restype", "directory")) + comp: Literal["rename"] = kwargs.pop("comp", _params.pop("comp", "rename")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _source_lease_id = None + _destination_lease_id = None + _file_attributes = None + _file_creation_time = None + _file_last_write_time = None + _file_change_time = None + if source_lease_access_conditions is not None: + _source_lease_id = source_lease_access_conditions.source_lease_id + if destination_lease_access_conditions is not None: + _destination_lease_id = destination_lease_access_conditions.destination_lease_id + if copy_file_smb_info is not None: + _file_attributes = copy_file_smb_info.file_attributes + _file_change_time = copy_file_smb_info.file_change_time + _file_creation_time = copy_file_smb_info.file_creation_time + _file_last_write_time = copy_file_smb_info.file_last_write_time + + _request = build_rename_request( + url=self._config.url, + rename_source=rename_source, + timeout=timeout, + replace_if_exists=replace_if_exists, + ignore_read_only=ignore_read_only, + source_lease_id=_source_lease_id, + destination_lease_id=_destination_lease_id, + file_attributes=_file_attributes, + file_creation_time=_file_creation_time, + file_last_write_time=_file_last_write_time, + file_change_time=_file_change_time, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + metadata=metadata, + allow_trailing_dot=self._config.allow_trailing_dot, + allow_source_trailing_dot=self._config.allow_source_trailing_dot, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_file_operations.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_file_operations.py new file mode 100644 index 00000000..d67f90d9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_file_operations.py @@ -0,0 +1,3755 @@ +# pylint: disable=too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +import sys +from typing import Any, Callable, Dict, IO, Iterator, Literal, Optional, TypeVar, Union + +from azure.core import PipelineClient +from azure.core.exceptions import ( + ClientAuthenticationError, + HttpResponseError, + ResourceExistsError, + ResourceNotFoundError, + ResourceNotModifiedError, + StreamClosedError, + StreamConsumedError, + map_error, +) +from azure.core.pipeline import PipelineResponse +from azure.core.rest import HttpRequest, HttpResponse +from azure.core.tracing.decorator import distributed_trace +from azure.core.utils import case_insensitive_dict + +from .. import models as _models +from .._configuration import AzureFileStorageConfiguration +from .._serialization import Deserializer, Serializer + +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore +T = TypeVar("T") +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +_SERIALIZER = Serializer() +_SERIALIZER.client_side_validation = False + + +def build_create_request( + url: str, + *, + file_content_length: int, + timeout: Optional[int] = None, + file_content_type: Optional[str] = None, + file_content_encoding: Optional[str] = None, + file_content_language: Optional[str] = None, + file_cache_control: Optional[str] = None, + file_content_md5: Optional[bytes] = None, + file_content_disposition: Optional[str] = None, + metadata: Optional[Dict[str, str]] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + file_attributes: str = "none", + file_creation_time: str = "now", + file_last_write_time: str = "now", + file_change_time: Optional[str] = None, + lease_id: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + nfs_file_type: Optional[Union[str, _models.NfsFileType]] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + file_type_constant: Literal["file"] = kwargs.pop("file_type_constant", _headers.pop("x-ms-type", "file")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + _headers["x-ms-content-length"] = _SERIALIZER.header("file_content_length", file_content_length, "int") + _headers["x-ms-type"] = _SERIALIZER.header("file_type_constant", file_type_constant, "str") + if file_content_type is not None: + _headers["x-ms-content-type"] = _SERIALIZER.header("file_content_type", file_content_type, "str") + if file_content_encoding is not None: + _headers["x-ms-content-encoding"] = _SERIALIZER.header("file_content_encoding", file_content_encoding, "str") + if file_content_language is not None: + _headers["x-ms-content-language"] = _SERIALIZER.header("file_content_language", file_content_language, "str") + if file_cache_control is not None: + _headers["x-ms-cache-control"] = _SERIALIZER.header("file_cache_control", file_cache_control, "str") + if file_content_md5 is not None: + _headers["x-ms-content-md5"] = _SERIALIZER.header("file_content_md5", file_content_md5, "bytearray") + if file_content_disposition is not None: + _headers["x-ms-content-disposition"] = _SERIALIZER.header( + "file_content_disposition", file_content_disposition, "str" + ) + if metadata is not None: + _headers["x-ms-meta"] = _SERIALIZER.header("metadata", metadata, "{str}") + if file_permission is not None: + _headers["x-ms-file-permission"] = _SERIALIZER.header("file_permission", file_permission, "str") + if file_permission_format is not None: + _headers["x-ms-file-permission-format"] = _SERIALIZER.header( + "file_permission_format", file_permission_format, "str" + ) + if file_permission_key is not None: + _headers["x-ms-file-permission-key"] = _SERIALIZER.header("file_permission_key", file_permission_key, "str") + if file_attributes is not None: + _headers["x-ms-file-attributes"] = _SERIALIZER.header("file_attributes", file_attributes, "str") + if file_creation_time is not None: + _headers["x-ms-file-creation-time"] = _SERIALIZER.header("file_creation_time", file_creation_time, "str") + if file_last_write_time is not None: + _headers["x-ms-file-last-write-time"] = _SERIALIZER.header("file_last_write_time", file_last_write_time, "str") + if file_change_time is not None: + _headers["x-ms-file-change-time"] = _SERIALIZER.header("file_change_time", file_change_time, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + if owner is not None: + _headers["x-ms-owner"] = _SERIALIZER.header("owner", owner, "str") + if group is not None: + _headers["x-ms-group"] = _SERIALIZER.header("group", group, "str") + if file_mode is not None: + _headers["x-ms-mode"] = _SERIALIZER.header("file_mode", file_mode, "str") + if nfs_file_type is not None: + _headers["x-ms-file-file-type"] = _SERIALIZER.header("nfs_file_type", nfs_file_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_download_request( + url: str, + *, + timeout: Optional[int] = None, + range: Optional[str] = None, + range_get_content_md5: Optional[bool] = None, + structured_body_type: Optional[str] = None, + lease_id: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if range is not None: + _headers["x-ms-range"] = _SERIALIZER.header("range", range, "str") + if range_get_content_md5 is not None: + _headers["x-ms-range-get-content-md5"] = _SERIALIZER.header( + "range_get_content_md5", range_get_content_md5, "bool" + ) + if structured_body_type is not None: + _headers["x-ms-structured-body"] = _SERIALIZER.header("structured_body_type", structured_body_type, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_get_properties_request( + url: str, + *, + sharesnapshot: Optional[str] = None, + timeout: Optional[int] = None, + lease_id: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="HEAD", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_delete_request( + url: str, + *, + timeout: Optional[int] = None, + lease_id: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_set_http_headers_request( + url: str, + *, + timeout: Optional[int] = None, + file_content_length: Optional[int] = None, + file_content_type: Optional[str] = None, + file_content_encoding: Optional[str] = None, + file_content_language: Optional[str] = None, + file_cache_control: Optional[str] = None, + file_content_md5: Optional[bytes] = None, + file_content_disposition: Optional[str] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + file_attributes: str = "none", + file_creation_time: str = "now", + file_last_write_time: str = "now", + file_change_time: Optional[str] = None, + lease_id: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if file_content_length is not None: + _headers["x-ms-content-length"] = _SERIALIZER.header("file_content_length", file_content_length, "int") + if file_content_type is not None: + _headers["x-ms-content-type"] = _SERIALIZER.header("file_content_type", file_content_type, "str") + if file_content_encoding is not None: + _headers["x-ms-content-encoding"] = _SERIALIZER.header("file_content_encoding", file_content_encoding, "str") + if file_content_language is not None: + _headers["x-ms-content-language"] = _SERIALIZER.header("file_content_language", file_content_language, "str") + if file_cache_control is not None: + _headers["x-ms-cache-control"] = _SERIALIZER.header("file_cache_control", file_cache_control, "str") + if file_content_md5 is not None: + _headers["x-ms-content-md5"] = _SERIALIZER.header("file_content_md5", file_content_md5, "bytearray") + if file_content_disposition is not None: + _headers["x-ms-content-disposition"] = _SERIALIZER.header( + "file_content_disposition", file_content_disposition, "str" + ) + if file_permission is not None: + _headers["x-ms-file-permission"] = _SERIALIZER.header("file_permission", file_permission, "str") + if file_permission_format is not None: + _headers["x-ms-file-permission-format"] = _SERIALIZER.header( + "file_permission_format", file_permission_format, "str" + ) + if file_permission_key is not None: + _headers["x-ms-file-permission-key"] = _SERIALIZER.header("file_permission_key", file_permission_key, "str") + if file_attributes is not None: + _headers["x-ms-file-attributes"] = _SERIALIZER.header("file_attributes", file_attributes, "str") + if file_creation_time is not None: + _headers["x-ms-file-creation-time"] = _SERIALIZER.header("file_creation_time", file_creation_time, "str") + if file_last_write_time is not None: + _headers["x-ms-file-last-write-time"] = _SERIALIZER.header("file_last_write_time", file_last_write_time, "str") + if file_change_time is not None: + _headers["x-ms-file-change-time"] = _SERIALIZER.header("file_change_time", file_change_time, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + if owner is not None: + _headers["x-ms-owner"] = _SERIALIZER.header("owner", owner, "str") + if group is not None: + _headers["x-ms-group"] = _SERIALIZER.header("group", group, "str") + if file_mode is not None: + _headers["x-ms-mode"] = _SERIALIZER.header("file_mode", file_mode, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_set_metadata_request( + url: str, + *, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + lease_id: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["metadata"] = kwargs.pop("comp", _params.pop("comp", "metadata")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + if metadata is not None: + _headers["x-ms-meta"] = _SERIALIZER.header("metadata", metadata, "{str}") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_acquire_lease_request( + url: str, + *, + timeout: Optional[int] = None, + duration: Optional[int] = None, + proposed_lease_id: Optional[str] = None, + request_id_parameter: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["acquire"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "acquire")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-lease-action"] = _SERIALIZER.header("action", action, "str") + if duration is not None: + _headers["x-ms-lease-duration"] = _SERIALIZER.header("duration", duration, "int") + if proposed_lease_id is not None: + _headers["x-ms-proposed-lease-id"] = _SERIALIZER.header("proposed_lease_id", proposed_lease_id, "str") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if request_id_parameter is not None: + _headers["x-ms-client-request-id"] = _SERIALIZER.header("request_id_parameter", request_id_parameter, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_release_lease_request( + url: str, + *, + lease_id: str, + timeout: Optional[int] = None, + request_id_parameter: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["release"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "release")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-lease-action"] = _SERIALIZER.header("action", action, "str") + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if request_id_parameter is not None: + _headers["x-ms-client-request-id"] = _SERIALIZER.header("request_id_parameter", request_id_parameter, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_change_lease_request( + url: str, + *, + lease_id: str, + timeout: Optional[int] = None, + proposed_lease_id: Optional[str] = None, + request_id_parameter: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["change"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "change")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-lease-action"] = _SERIALIZER.header("action", action, "str") + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if proposed_lease_id is not None: + _headers["x-ms-proposed-lease-id"] = _SERIALIZER.header("proposed_lease_id", proposed_lease_id, "str") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if request_id_parameter is not None: + _headers["x-ms-client-request-id"] = _SERIALIZER.header("request_id_parameter", request_id_parameter, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_break_lease_request( + url: str, + *, + timeout: Optional[int] = None, + lease_id: Optional[str] = None, + request_id_parameter: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["break"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "break")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-lease-action"] = _SERIALIZER.header("action", action, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if request_id_parameter is not None: + _headers["x-ms-client-request-id"] = _SERIALIZER.header("request_id_parameter", request_id_parameter, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_upload_range_request( + url: str, + *, + range: str, + content_length: int, + timeout: Optional[int] = None, + file_range_write: Union[str, _models.FileRangeWriteType] = "update", + content_md5: Optional[bytes] = None, + lease_id: Optional[str] = None, + file_last_written_mode: Optional[Union[str, _models.FileLastWrittenMode]] = None, + structured_body_type: Optional[str] = None, + structured_content_length: Optional[int] = None, + content: Optional[IO[bytes]] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["range"] = kwargs.pop("comp", _params.pop("comp", "range")) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-range"] = _SERIALIZER.header("range", range, "str") + _headers["x-ms-write"] = _SERIALIZER.header("file_range_write", file_range_write, "str") + _headers["Content-Length"] = _SERIALIZER.header("content_length", content_length, "int") + if content_md5 is not None: + _headers["Content-MD5"] = _SERIALIZER.header("content_md5", content_md5, "bytearray") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if file_last_written_mode is not None: + _headers["x-ms-file-last-write-time"] = _SERIALIZER.header( + "file_last_written_mode", file_last_written_mode, "str" + ) + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + if structured_body_type is not None: + _headers["x-ms-structured-body"] = _SERIALIZER.header("structured_body_type", structured_body_type, "str") + if structured_content_length is not None: + _headers["x-ms-structured-content-length"] = _SERIALIZER.header( + "structured_content_length", structured_content_length, "int" + ) + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, content=content, **kwargs) + + +def build_upload_range_from_url_request( + url: str, + *, + range: str, + copy_source: str, + content_length: int, + timeout: Optional[int] = None, + source_range: Optional[str] = None, + source_content_crc64: Optional[bytes] = None, + source_if_match_crc64: Optional[bytes] = None, + source_if_none_match_crc64: Optional[bytes] = None, + lease_id: Optional[str] = None, + copy_source_authorization: Optional[str] = None, + file_last_written_mode: Optional[Union[str, _models.FileLastWrittenMode]] = None, + allow_trailing_dot: Optional[bool] = None, + allow_source_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["range"] = kwargs.pop("comp", _params.pop("comp", "range")) + file_range_write_from_url: Literal["update"] = kwargs.pop( + "file_range_write_from_url", _headers.pop("x-ms-write", "update") + ) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-range"] = _SERIALIZER.header("range", range, "str") + _headers["x-ms-copy-source"] = _SERIALIZER.header("copy_source", copy_source, "str") + if source_range is not None: + _headers["x-ms-source-range"] = _SERIALIZER.header("source_range", source_range, "str") + _headers["x-ms-write"] = _SERIALIZER.header("file_range_write_from_url", file_range_write_from_url, "str") + _headers["Content-Length"] = _SERIALIZER.header("content_length", content_length, "int") + if source_content_crc64 is not None: + _headers["x-ms-source-content-crc64"] = _SERIALIZER.header( + "source_content_crc64", source_content_crc64, "bytearray" + ) + if source_if_match_crc64 is not None: + _headers["x-ms-source-if-match-crc64"] = _SERIALIZER.header( + "source_if_match_crc64", source_if_match_crc64, "bytearray" + ) + if source_if_none_match_crc64 is not None: + _headers["x-ms-source-if-none-match-crc64"] = _SERIALIZER.header( + "source_if_none_match_crc64", source_if_none_match_crc64, "bytearray" + ) + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if copy_source_authorization is not None: + _headers["x-ms-copy-source-authorization"] = _SERIALIZER.header( + "copy_source_authorization", copy_source_authorization, "str" + ) + if file_last_written_mode is not None: + _headers["x-ms-file-last-write-time"] = _SERIALIZER.header( + "file_last_written_mode", file_last_written_mode, "str" + ) + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if allow_source_trailing_dot is not None: + _headers["x-ms-source-allow-trailing-dot"] = _SERIALIZER.header( + "allow_source_trailing_dot", allow_source_trailing_dot, "bool" + ) + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_get_range_list_request( + url: str, + *, + sharesnapshot: Optional[str] = None, + prevsharesnapshot: Optional[str] = None, + timeout: Optional[int] = None, + range: Optional[str] = None, + lease_id: Optional[str] = None, + support_rename: Optional[bool] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["rangelist"] = kwargs.pop("comp", _params.pop("comp", "rangelist")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + if prevsharesnapshot is not None: + _params["prevsharesnapshot"] = _SERIALIZER.query("prevsharesnapshot", prevsharesnapshot, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if range is not None: + _headers["x-ms-range"] = _SERIALIZER.header("range", range, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + if support_rename is not None: + _headers["x-ms-file-support-rename"] = _SERIALIZER.header("support_rename", support_rename, "bool") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_start_copy_request( + url: str, + *, + copy_source: str, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + file_permission_copy_mode: Optional[Union[str, _models.PermissionCopyModeType]] = None, + ignore_read_only: Optional[bool] = None, + file_attributes: Optional[str] = None, + file_creation_time: Optional[str] = None, + file_last_write_time: Optional[str] = None, + file_change_time: Optional[str] = None, + set_archive_attribute: Optional[bool] = None, + lease_id: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + file_mode_copy_mode: Optional[Union[str, _models.ModeCopyMode]] = None, + file_owner_copy_mode: Optional[Union[str, _models.OwnerCopyMode]] = None, + allow_trailing_dot: Optional[bool] = None, + allow_source_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if metadata is not None: + _headers["x-ms-meta"] = _SERIALIZER.header("metadata", metadata, "{str}") + _headers["x-ms-copy-source"] = _SERIALIZER.header("copy_source", copy_source, "str") + if file_permission is not None: + _headers["x-ms-file-permission"] = _SERIALIZER.header("file_permission", file_permission, "str") + if file_permission_format is not None: + _headers["x-ms-file-permission-format"] = _SERIALIZER.header( + "file_permission_format", file_permission_format, "str" + ) + if file_permission_key is not None: + _headers["x-ms-file-permission-key"] = _SERIALIZER.header("file_permission_key", file_permission_key, "str") + if file_permission_copy_mode is not None: + _headers["x-ms-file-permission-copy-mode"] = _SERIALIZER.header( + "file_permission_copy_mode", file_permission_copy_mode, "str" + ) + if ignore_read_only is not None: + _headers["x-ms-file-copy-ignore-readonly"] = _SERIALIZER.header("ignore_read_only", ignore_read_only, "bool") + if file_attributes is not None: + _headers["x-ms-file-attributes"] = _SERIALIZER.header("file_attributes", file_attributes, "str") + if file_creation_time is not None: + _headers["x-ms-file-creation-time"] = _SERIALIZER.header("file_creation_time", file_creation_time, "str") + if file_last_write_time is not None: + _headers["x-ms-file-last-write-time"] = _SERIALIZER.header("file_last_write_time", file_last_write_time, "str") + if file_change_time is not None: + _headers["x-ms-file-change-time"] = _SERIALIZER.header("file_change_time", file_change_time, "str") + if set_archive_attribute is not None: + _headers["x-ms-file-copy-set-archive"] = _SERIALIZER.header( + "set_archive_attribute", set_archive_attribute, "bool" + ) + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if allow_source_trailing_dot is not None: + _headers["x-ms-source-allow-trailing-dot"] = _SERIALIZER.header( + "allow_source_trailing_dot", allow_source_trailing_dot, "bool" + ) + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + if owner is not None: + _headers["x-ms-owner"] = _SERIALIZER.header("owner", owner, "str") + if group is not None: + _headers["x-ms-group"] = _SERIALIZER.header("group", group, "str") + if file_mode is not None: + _headers["x-ms-mode"] = _SERIALIZER.header("file_mode", file_mode, "str") + if file_mode_copy_mode is not None: + _headers["x-ms-file-mode-copy-mode"] = _SERIALIZER.header("file_mode_copy_mode", file_mode_copy_mode, "str") + if file_owner_copy_mode is not None: + _headers["x-ms-file-owner-copy-mode"] = _SERIALIZER.header("file_owner_copy_mode", file_owner_copy_mode, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_abort_copy_request( + url: str, + *, + copy_id: str, + timeout: Optional[int] = None, + lease_id: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["copy"] = kwargs.pop("comp", _params.pop("comp", "copy")) + copy_action_abort_constant: Literal["abort"] = kwargs.pop( + "copy_action_abort_constant", _headers.pop("x-ms-copy-action", "abort") + ) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + _params["copyid"] = _SERIALIZER.query("copy_id", copy_id, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-copy-action"] = _SERIALIZER.header("copy_action_abort_constant", copy_action_abort_constant, "str") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_list_handles_request( + url: str, + *, + marker: Optional[str] = None, + maxresults: Optional[int] = None, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["listhandles"] = kwargs.pop("comp", _params.pop("comp", "listhandles")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if marker is not None: + _params["marker"] = _SERIALIZER.query("marker", marker, "str") + if maxresults is not None: + _params["maxresults"] = _SERIALIZER.query("maxresults", maxresults, "int", minimum=1) + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_force_close_handles_request( + url: str, + *, + handle_id: str, + timeout: Optional[int] = None, + marker: Optional[str] = None, + sharesnapshot: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["forceclosehandles"] = kwargs.pop("comp", _params.pop("comp", "forceclosehandles")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + if marker is not None: + _params["marker"] = _SERIALIZER.query("marker", marker, "str") + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + + # Construct headers + _headers["x-ms-handle-id"] = _SERIALIZER.header("handle_id", handle_id, "str") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_rename_request( + url: str, + *, + rename_source: str, + timeout: Optional[int] = None, + replace_if_exists: Optional[bool] = None, + ignore_read_only: Optional[bool] = None, + source_lease_id: Optional[str] = None, + destination_lease_id: Optional[str] = None, + file_attributes: Optional[str] = None, + file_creation_time: Optional[str] = None, + file_last_write_time: Optional[str] = None, + file_change_time: Optional[str] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + metadata: Optional[Dict[str, str]] = None, + file_content_type: Optional[str] = None, + allow_trailing_dot: Optional[bool] = None, + allow_source_trailing_dot: Optional[bool] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["rename"] = kwargs.pop("comp", _params.pop("comp", "rename")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + _headers["x-ms-file-rename-source"] = _SERIALIZER.header("rename_source", rename_source, "str") + if replace_if_exists is not None: + _headers["x-ms-file-rename-replace-if-exists"] = _SERIALIZER.header( + "replace_if_exists", replace_if_exists, "bool" + ) + if ignore_read_only is not None: + _headers["x-ms-file-rename-ignore-readonly"] = _SERIALIZER.header("ignore_read_only", ignore_read_only, "bool") + if source_lease_id is not None: + _headers["x-ms-source-lease-id"] = _SERIALIZER.header("source_lease_id", source_lease_id, "str") + if destination_lease_id is not None: + _headers["x-ms-destination-lease-id"] = _SERIALIZER.header("destination_lease_id", destination_lease_id, "str") + if file_attributes is not None: + _headers["x-ms-file-attributes"] = _SERIALIZER.header("file_attributes", file_attributes, "str") + if file_creation_time is not None: + _headers["x-ms-file-creation-time"] = _SERIALIZER.header("file_creation_time", file_creation_time, "str") + if file_last_write_time is not None: + _headers["x-ms-file-last-write-time"] = _SERIALIZER.header("file_last_write_time", file_last_write_time, "str") + if file_change_time is not None: + _headers["x-ms-file-change-time"] = _SERIALIZER.header("file_change_time", file_change_time, "str") + if file_permission is not None: + _headers["x-ms-file-permission"] = _SERIALIZER.header("file_permission", file_permission, "str") + if file_permission_format is not None: + _headers["x-ms-file-permission-format"] = _SERIALIZER.header( + "file_permission_format", file_permission_format, "str" + ) + if file_permission_key is not None: + _headers["x-ms-file-permission-key"] = _SERIALIZER.header("file_permission_key", file_permission_key, "str") + if metadata is not None: + _headers["x-ms-meta"] = _SERIALIZER.header("metadata", metadata, "{str}") + if file_content_type is not None: + _headers["x-ms-content-type"] = _SERIALIZER.header("file_content_type", file_content_type, "str") + if allow_trailing_dot is not None: + _headers["x-ms-allow-trailing-dot"] = _SERIALIZER.header("allow_trailing_dot", allow_trailing_dot, "bool") + if allow_source_trailing_dot is not None: + _headers["x-ms-source-allow-trailing-dot"] = _SERIALIZER.header( + "allow_source_trailing_dot", allow_source_trailing_dot, "bool" + ) + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_create_symbolic_link_request( + url: str, + *, + link_text: str, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + file_creation_time: str = "now", + file_last_write_time: str = "now", + request_id_parameter: Optional[str] = None, + lease_id: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["symboliclink"] = kwargs.pop("restype", _params.pop("restype", "symboliclink")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if metadata is not None: + _headers["x-ms-meta"] = _SERIALIZER.header("metadata", metadata, "{str}") + if file_creation_time is not None: + _headers["x-ms-file-creation-time"] = _SERIALIZER.header("file_creation_time", file_creation_time, "str") + if file_last_write_time is not None: + _headers["x-ms-file-last-write-time"] = _SERIALIZER.header("file_last_write_time", file_last_write_time, "str") + if request_id_parameter is not None: + _headers["x-ms-client-request-id"] = _SERIALIZER.header("request_id_parameter", request_id_parameter, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if owner is not None: + _headers["x-ms-owner"] = _SERIALIZER.header("owner", owner, "str") + if group is not None: + _headers["x-ms-group"] = _SERIALIZER.header("group", group, "str") + _headers["x-ms-link-text"] = _SERIALIZER.header("link_text", link_text, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_get_symbolic_link_request( + url: str, + *, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["symboliclink"] = kwargs.pop("restype", _params.pop("restype", "symboliclink")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if request_id_parameter is not None: + _headers["x-ms-client-request-id"] = _SERIALIZER.header("request_id_parameter", request_id_parameter, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_create_hard_link_request( + url: str, + *, + target_file: str, + timeout: Optional[int] = None, + request_id_parameter: Optional[str] = None, + lease_id: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["hardlink"] = kwargs.pop("restype", _params.pop("restype", "hardlink")) + file_type_constant: Literal["file"] = kwargs.pop("file_type_constant", _headers.pop("x-ms-type", "file")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + _headers["x-ms-type"] = _SERIALIZER.header("file_type_constant", file_type_constant, "str") + if request_id_parameter is not None: + _headers["x-ms-client-request-id"] = _SERIALIZER.header("request_id_parameter", request_id_parameter, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + _headers["x-ms-file-target-file"] = _SERIALIZER.header("target_file", target_file, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +class FileOperations: # pylint: disable=too-many-public-methods + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.storage.fileshare.AzureFileStorage`'s + :attr:`file` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs): + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AzureFileStorageConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace + def create( # pylint: disable=inconsistent-return-statements + self, + file_content_length: int, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + file_attributes: str = "none", + file_creation_time: str = "now", + file_last_write_time: str = "now", + file_change_time: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + nfs_file_type: Optional[Union[str, _models.NfsFileType]] = None, + file_http_headers: Optional[_models.FileHTTPHeaders] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Creates a new file or replaces a file. Note it only initializes the file with no content. + + :param file_content_length: Specifies the maximum size for the file, up to 4 TB. Required. + :type file_content_length: int + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param file_attributes: If specified, the provided file attributes shall be set. Default value: + ‘Archive’ for file and ‘Directory’ for directory. ‘None’ can also be specified as default. + Default value is "none". + :type file_attributes: str + :param file_creation_time: Creation time for the file/directory. Default value: Now. Default + value is "now". + :type file_creation_time: str + :param file_last_write_time: Last write time for the file/directory. Default value: Now. + Default value is "now". + :type file_last_write_time: str + :param file_change_time: Change time for the file/directory. Default value: Now. Default value + is None. + :type file_change_time: str + :param owner: Optional, NFS only. The owner of the file or directory. Default value is None. + :type owner: str + :param group: Optional, NFS only. The owning group of the file or directory. Default value is + None. + :type group: str + :param file_mode: Optional, NFS only. The file mode of the file or directory. Default value is + None. + :type file_mode: str + :param nfs_file_type: Optional, NFS only. Type of the file or directory. Known values are: + "Regular", "Directory", and "SymLink". Default value is None. + :type nfs_file_type: str or ~azure.storage.fileshare.models.NfsFileType + :param file_http_headers: Parameter group. Default value is None. + :type file_http_headers: ~azure.storage.fileshare.models.FileHTTPHeaders + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = kwargs.pop("params", {}) or {} + + file_type_constant: Literal["file"] = kwargs.pop("file_type_constant", _headers.pop("x-ms-type", "file")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _file_content_type = None + _file_content_encoding = None + _file_content_language = None + _file_cache_control = None + _file_content_md5 = None + _file_content_disposition = None + _lease_id = None + if file_http_headers is not None: + _file_cache_control = file_http_headers.file_cache_control + _file_content_disposition = file_http_headers.file_content_disposition + _file_content_encoding = file_http_headers.file_content_encoding + _file_content_language = file_http_headers.file_content_language + _file_content_md5 = file_http_headers.file_content_md5 + _file_content_type = file_http_headers.file_content_type + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_create_request( + url=self._config.url, + file_content_length=file_content_length, + timeout=timeout, + file_content_type=_file_content_type, + file_content_encoding=_file_content_encoding, + file_content_language=_file_content_language, + file_cache_control=_file_cache_control, + file_content_md5=_file_content_md5, + file_content_disposition=_file_content_disposition, + metadata=metadata, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + file_attributes=file_attributes, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + file_change_time=file_change_time, + lease_id=_lease_id, + owner=owner, + group=group, + file_mode=file_mode, + nfs_file_type=nfs_file_type, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + file_type_constant=file_type_constant, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-file-file-type"] = self._deserialize("str", response.headers.get("x-ms-file-file-type")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def download( + self, + timeout: Optional[int] = None, + range: Optional[str] = None, + range_get_content_md5: Optional[bool] = None, + structured_body_type: Optional[str] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> Iterator[bytes]: + # pylint: disable=line-too-long + """Reads or downloads a file from the system, including its metadata and properties. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param range: Return file data only from the specified byte range. Default value is None. + :type range: str + :param range_get_content_md5: When this header is set to true and specified together with the + Range header, the service returns the MD5 hash for the range, as long as the range is less than + or equal to 4 MB in size. Default value is None. + :type range_get_content_md5: bool + :param structured_body_type: Specifies the response content should be returned as a structured + message and specifies the message schema version and properties. Default value is None. + :type structured_body_type: str + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: Iterator[bytes] or the result of cls(response) + :rtype: Iterator[bytes] + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[Iterator[bytes]] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_download_request( + url=self._config.url, + timeout=timeout, + range=range, + range_get_content_md5=range_get_content_md5, + structured_body_type=structured_body_type, + lease_id=_lease_id, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _decompress = kwargs.pop("decompress", True) + _stream = True + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200, 206]: + try: + response.read() # Load the body in memory and close the socket + except (StreamConsumedError, StreamClosedError): + pass + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-meta"] = self._deserialize("{str}", response.headers.get("x-ms-meta")) + response_headers["Content-Length"] = self._deserialize("int", response.headers.get("Content-Length")) + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + response_headers["Content-Range"] = self._deserialize("str", response.headers.get("Content-Range")) + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Content-MD5"] = self._deserialize("bytearray", response.headers.get("Content-MD5")) + response_headers["Content-Encoding"] = self._deserialize("str", response.headers.get("Content-Encoding")) + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Content-Disposition"] = self._deserialize("str", response.headers.get("Content-Disposition")) + response_headers["Content-Language"] = self._deserialize("str", response.headers.get("Content-Language")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Accept-Ranges"] = self._deserialize("str", response.headers.get("Accept-Ranges")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-copy-completion-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-copy-completion-time") + ) + response_headers["x-ms-copy-status-description"] = self._deserialize( + "str", response.headers.get("x-ms-copy-status-description") + ) + response_headers["x-ms-copy-id"] = self._deserialize("str", response.headers.get("x-ms-copy-id")) + response_headers["x-ms-copy-progress"] = self._deserialize("str", response.headers.get("x-ms-copy-progress")) + response_headers["x-ms-copy-source"] = self._deserialize("str", response.headers.get("x-ms-copy-source")) + response_headers["x-ms-copy-status"] = self._deserialize("str", response.headers.get("x-ms-copy-status")) + response_headers["x-ms-content-md5"] = self._deserialize("bytearray", response.headers.get("x-ms-content-md5")) + response_headers["x-ms-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-server-encrypted") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-lease-duration"] = self._deserialize("str", response.headers.get("x-ms-lease-duration")) + response_headers["x-ms-lease-state"] = self._deserialize("str", response.headers.get("x-ms-lease-state")) + response_headers["x-ms-lease-status"] = self._deserialize("str", response.headers.get("x-ms-lease-status")) + response_headers["x-ms-structured-body"] = self._deserialize( + "str", response.headers.get("x-ms-structured-body") + ) + response_headers["x-ms-structured-content-length"] = self._deserialize( + "int", response.headers.get("x-ms-structured-content-length") + ) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-link-count"] = self._deserialize("int", response.headers.get("x-ms-link-count")) + + deserialized = response.stream_download(self._client._pipeline, decompress=_decompress) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def get_properties( # pylint: disable=inconsistent-return-statements + self, + sharesnapshot: Optional[str] = None, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Returns all user-defined metadata, standard HTTP properties, and system properties for the + file. It does not return the content of the file. + + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_get_properties_request( + url=self._config.url, + sharesnapshot=sharesnapshot, + timeout=timeout, + lease_id=_lease_id, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-meta"] = self._deserialize("{str}", response.headers.get("x-ms-meta")) + response_headers["x-ms-type"] = self._deserialize("str", response.headers.get("x-ms-type")) + response_headers["Content-Length"] = self._deserialize("int", response.headers.get("Content-Length")) + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Content-MD5"] = self._deserialize("bytearray", response.headers.get("Content-MD5")) + response_headers["Content-Encoding"] = self._deserialize("str", response.headers.get("Content-Encoding")) + response_headers["Cache-Control"] = self._deserialize("str", response.headers.get("Cache-Control")) + response_headers["Content-Disposition"] = self._deserialize("str", response.headers.get("Content-Disposition")) + response_headers["Content-Language"] = self._deserialize("str", response.headers.get("Content-Language")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-copy-completion-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-copy-completion-time") + ) + response_headers["x-ms-copy-status-description"] = self._deserialize( + "str", response.headers.get("x-ms-copy-status-description") + ) + response_headers["x-ms-copy-id"] = self._deserialize("str", response.headers.get("x-ms-copy-id")) + response_headers["x-ms-copy-progress"] = self._deserialize("str", response.headers.get("x-ms-copy-progress")) + response_headers["x-ms-copy-source"] = self._deserialize("str", response.headers.get("x-ms-copy-source")) + response_headers["x-ms-copy-status"] = self._deserialize("str", response.headers.get("x-ms-copy-status")) + response_headers["x-ms-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-server-encrypted") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-lease-duration"] = self._deserialize("str", response.headers.get("x-ms-lease-duration")) + response_headers["x-ms-lease-state"] = self._deserialize("str", response.headers.get("x-ms-lease-state")) + response_headers["x-ms-lease-status"] = self._deserialize("str", response.headers.get("x-ms-lease-status")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-link-count"] = self._deserialize("int", response.headers.get("x-ms-link-count")) + response_headers["x-ms-file-file-type"] = self._deserialize("str", response.headers.get("x-ms-file-file-type")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def delete( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """removes the file from the storage account. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_delete_request( + url=self._config.url, + timeout=timeout, + lease_id=_lease_id, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-link-count"] = self._deserialize("int", response.headers.get("x-ms-link-count")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def set_http_headers( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + file_content_length: Optional[int] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + file_attributes: str = "none", + file_creation_time: str = "now", + file_last_write_time: str = "now", + file_change_time: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + file_http_headers: Optional[_models.FileHTTPHeaders] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Sets HTTP headers on the file. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param file_content_length: Resizes a file to the specified size. If the specified byte value + is less than the current size of the file, then all ranges above the specified byte value are + cleared. Default value is None. + :type file_content_length: int + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param file_attributes: If specified, the provided file attributes shall be set. Default value: + ‘Archive’ for file and ‘Directory’ for directory. ‘None’ can also be specified as default. + Default value is "none". + :type file_attributes: str + :param file_creation_time: Creation time for the file/directory. Default value: Now. Default + value is "now". + :type file_creation_time: str + :param file_last_write_time: Last write time for the file/directory. Default value: Now. + Default value is "now". + :type file_last_write_time: str + :param file_change_time: Change time for the file/directory. Default value: Now. Default value + is None. + :type file_change_time: str + :param owner: Optional, NFS only. The owner of the file or directory. Default value is None. + :type owner: str + :param group: Optional, NFS only. The owning group of the file or directory. Default value is + None. + :type group: str + :param file_mode: Optional, NFS only. The file mode of the file or directory. Default value is + None. + :type file_mode: str + :param file_http_headers: Parameter group. Default value is None. + :type file_http_headers: ~azure.storage.fileshare.models.FileHTTPHeaders + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _file_content_type = None + _file_content_encoding = None + _file_content_language = None + _file_cache_control = None + _file_content_md5 = None + _file_content_disposition = None + _lease_id = None + if file_http_headers is not None: + _file_cache_control = file_http_headers.file_cache_control + _file_content_disposition = file_http_headers.file_content_disposition + _file_content_encoding = file_http_headers.file_content_encoding + _file_content_language = file_http_headers.file_content_language + _file_content_md5 = file_http_headers.file_content_md5 + _file_content_type = file_http_headers.file_content_type + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_set_http_headers_request( + url=self._config.url, + timeout=timeout, + file_content_length=file_content_length, + file_content_type=_file_content_type, + file_content_encoding=_file_content_encoding, + file_content_language=_file_content_language, + file_cache_control=_file_cache_control, + file_content_md5=_file_content_md5, + file_content_disposition=_file_content_disposition, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + file_attributes=file_attributes, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + file_change_time=file_change_time, + lease_id=_lease_id, + owner=owner, + group=group, + file_mode=file_mode, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-link-count"] = self._deserialize("int", response.headers.get("x-ms-link-count")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def set_metadata( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Updates user-defined metadata for the specified file. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["metadata"] = kwargs.pop("comp", _params.pop("comp", "metadata")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_set_metadata_request( + url=self._config.url, + timeout=timeout, + metadata=metadata, + lease_id=_lease_id, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def acquire_lease( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + duration: Optional[int] = None, + proposed_lease_id: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """[Update] The Lease File operation establishes and manages a lock on a file for write and delete + operations. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param duration: Specifies the duration of the lease, in seconds, or negative one (-1) for a + lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease + duration cannot be changed using renew or change. Default value is None. + :type duration: int + :param proposed_lease_id: Proposed lease ID, in a GUID string format. The File service returns + 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid + Constructor (String) for a list of valid GUID string formats. Default value is None. + :type proposed_lease_id: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["acquire"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "acquire")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_acquire_lease_request( + url=self._config.url, + timeout=timeout, + duration=duration, + proposed_lease_id=proposed_lease_id, + request_id_parameter=request_id_parameter, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def release_lease( # pylint: disable=inconsistent-return-statements + self, lease_id: str, timeout: Optional[int] = None, request_id_parameter: Optional[str] = None, **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """[Update] The Lease File operation establishes and manages a lock on a file for write and delete + operations. + + :param lease_id: Specifies the current lease ID on the resource. Required. + :type lease_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["release"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "release")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_release_lease_request( + url=self._config.url, + lease_id=lease_id, + timeout=timeout, + request_id_parameter=request_id_parameter, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def change_lease( # pylint: disable=inconsistent-return-statements + self, + lease_id: str, + timeout: Optional[int] = None, + proposed_lease_id: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """[Update] The Lease File operation establishes and manages a lock on a file for write and delete + operations. + + :param lease_id: Specifies the current lease ID on the resource. Required. + :type lease_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param proposed_lease_id: Proposed lease ID, in a GUID string format. The File service returns + 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid + Constructor (String) for a list of valid GUID string formats. Default value is None. + :type proposed_lease_id: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["change"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "change")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_change_lease_request( + url=self._config.url, + lease_id=lease_id, + timeout=timeout, + proposed_lease_id=proposed_lease_id, + request_id_parameter=request_id_parameter, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def break_lease( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + request_id_parameter: Optional[str] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """[Update] The Lease File operation establishes and manages a lock on a file for write and delete + operations. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["break"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "break")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_break_lease_request( + url=self._config.url, + timeout=timeout, + lease_id=_lease_id, + request_id_parameter=request_id_parameter, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def upload_range( # pylint: disable=inconsistent-return-statements + self, + range: str, + content_length: int, + timeout: Optional[int] = None, + file_range_write: Union[str, _models.FileRangeWriteType] = "update", + content_md5: Optional[bytes] = None, + file_last_written_mode: Optional[Union[str, _models.FileLastWrittenMode]] = None, + structured_body_type: Optional[str] = None, + structured_content_length: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + optionalbody: Optional[IO[bytes]] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Upload a range of bytes to a file. + + :param range: Specifies the range of bytes to be written. Both the start and end of the range + must be specified. For an update operation, the range can be up to 4 MB in size. For a clear + operation, the range can be up to the value of the file's full size. The File service accepts + only a single byte range for the Range and 'x-ms-range' headers, and the byte range must be + specified in the following format: bytes=startByte-endByte. Required. + :type range: str + :param content_length: Specifies the number of bytes being transmitted in the request body. + When the x-ms-write header is set to clear, the value of this header must be set to zero. + Required. + :type content_length: int + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param file_range_write: Specify one of the following options: - Update: Writes the bytes + specified by the request body into the specified range. The Range and Content-Length headers + must match to perform the update. - Clear: Clears the specified range and releases the space + used in storage for that range. To clear a range, set the Content-Length header to zero, and + set the Range header to a value that indicates the range to clear, up to maximum file size. + Known values are: "update" and "clear". Default value is "update". + :type file_range_write: str or ~azure.storage.fileshare.models.FileRangeWriteType + :param content_md5: An MD5 hash of the content. This hash is used to verify the integrity of + the data during transport. When the Content-MD5 header is specified, the File service compares + the hash of the content that has arrived with the header value that was sent. If the two hashes + do not match, the operation will fail with error code 400 (Bad Request). Default value is None. + :type content_md5: bytes + :param file_last_written_mode: If the file last write time should be preserved or overwritten. + Known values are: "Now" and "Preserve". Default value is None. + :type file_last_written_mode: str or ~azure.storage.fileshare.models.FileLastWrittenMode + :param structured_body_type: Required if the request body is a structured message. Specifies + the message schema version and properties. Default value is None. + :type structured_body_type: str + :param structured_content_length: Required if the request body is a structured message. + Specifies the length of the blob/file content inside the message body. Will always be smaller + than Content-Length. Default value is None. + :type structured_content_length: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :param optionalbody: Initial data. Default value is None. + :type optionalbody: IO[bytes] + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["range"] = kwargs.pop("comp", _params.pop("comp", "range")) + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/octet-stream")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + _content = optionalbody + + _request = build_upload_range_request( + url=self._config.url, + range=range, + content_length=content_length, + timeout=timeout, + file_range_write=file_range_write, + content_md5=content_md5, + lease_id=_lease_id, + file_last_written_mode=file_last_written_mode, + structured_body_type=structured_body_type, + structured_content_length=structured_content_length, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + content_type=content_type, + version=self._config.version, + content=_content, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["Content-MD5"] = self._deserialize("bytearray", response.headers.get("Content-MD5")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-structured-body"] = self._deserialize( + "str", response.headers.get("x-ms-structured-body") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def upload_range_from_url( # pylint: disable=inconsistent-return-statements + self, + range: str, + copy_source: str, + content_length: int, + timeout: Optional[int] = None, + source_range: Optional[str] = None, + source_content_crc64: Optional[bytes] = None, + copy_source_authorization: Optional[str] = None, + file_last_written_mode: Optional[Union[str, _models.FileLastWrittenMode]] = None, + source_modified_access_conditions: Optional[_models.SourceModifiedAccessConditions] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Upload a range of bytes to a file where the contents are read from a URL. + + :param range: Writes data to the specified byte range in the file. Required. + :type range: str + :param copy_source: Specifies the URL of the source file or blob, up to 2 KB in length. To copy + a file to another file within the same storage account, you may use Shared Key to authenticate + the source file. If you are copying a file from another storage account, or if you are copying + a blob from the same storage account or another storage account, then you must authenticate the + source file or blob using a shared access signature. If the source is a public blob, no + authentication is required to perform the copy operation. A file in a share snapshot can also + be specified as a copy source. Required. + :type copy_source: str + :param content_length: Specifies the number of bytes being transmitted in the request body. + When the x-ms-write header is set to clear, the value of this header must be set to zero. + Required. + :type content_length: int + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param source_range: Bytes of source data in the specified range. Default value is None. + :type source_range: str + :param source_content_crc64: Specify the crc64 calculated for the range of bytes that must be + read from the copy source. Default value is None. + :type source_content_crc64: bytes + :param copy_source_authorization: Only Bearer type is supported. Credentials should be a valid + OAuth access token to copy source. Default value is None. + :type copy_source_authorization: str + :param file_last_written_mode: If the file last write time should be preserved or overwritten. + Known values are: "Now" and "Preserve". Default value is None. + :type file_last_written_mode: str or ~azure.storage.fileshare.models.FileLastWrittenMode + :param source_modified_access_conditions: Parameter group. Default value is None. + :type source_modified_access_conditions: + ~azure.storage.fileshare.models.SourceModifiedAccessConditions + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["range"] = kwargs.pop("comp", _params.pop("comp", "range")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _source_if_match_crc64 = None + _source_if_none_match_crc64 = None + _lease_id = None + if source_modified_access_conditions is not None: + _source_if_match_crc64 = source_modified_access_conditions.source_if_match_crc64 + _source_if_none_match_crc64 = source_modified_access_conditions.source_if_none_match_crc64 + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_upload_range_from_url_request( + url=self._config.url, + range=range, + copy_source=copy_source, + content_length=content_length, + timeout=timeout, + source_range=source_range, + source_content_crc64=source_content_crc64, + source_if_match_crc64=_source_if_match_crc64, + source_if_none_match_crc64=_source_if_none_match_crc64, + lease_id=_lease_id, + copy_source_authorization=copy_source_authorization, + file_last_written_mode=file_last_written_mode, + allow_trailing_dot=self._config.allow_trailing_dot, + allow_source_trailing_dot=self._config.allow_source_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + file_range_write_from_url=self._config.file_range_write_from_url, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-content-crc64"] = self._deserialize( + "bytearray", response.headers.get("x-ms-content-crc64") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def get_range_list( + self, + sharesnapshot: Optional[str] = None, + prevsharesnapshot: Optional[str] = None, + timeout: Optional[int] = None, + range: Optional[str] = None, + support_rename: Optional[bool] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> _models.ShareFileRangeList: + # pylint: disable=line-too-long + """Returns the list of valid ranges for a file. + + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param prevsharesnapshot: The previous snapshot parameter is an opaque DateTime value that, + when present, specifies the previous snapshot. Default value is None. + :type prevsharesnapshot: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param range: Specifies the range of bytes over which to list ranges, inclusively. Default + value is None. + :type range: str + :param support_rename: This header is allowed only when PrevShareSnapshot query parameter is + set. Determines whether the changed ranges for a file that has been renamed or moved between + the target snapshot (or the live file) and the previous snapshot should be listed. If the value + is true, the valid changed ranges for the file will be returned. If the value is false, the + operation will result in a failure with 409 (Conflict) response. The default value is false. + Default value is None. + :type support_rename: bool + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: ShareFileRangeList or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.ShareFileRangeList + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["rangelist"] = kwargs.pop("comp", _params.pop("comp", "rangelist")) + cls: ClsType[_models.ShareFileRangeList] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_get_range_list_request( + url=self._config.url, + sharesnapshot=sharesnapshot, + prevsharesnapshot=prevsharesnapshot, + timeout=timeout, + range=range, + lease_id=_lease_id, + support_rename=support_rename, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["x-ms-content-length"] = self._deserialize("int", response.headers.get("x-ms-content-length")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("ShareFileRangeList", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def start_copy( # pylint: disable=inconsistent-return-statements + self, + copy_source: str, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + file_mode: Optional[str] = None, + file_mode_copy_mode: Optional[Union[str, _models.ModeCopyMode]] = None, + file_owner_copy_mode: Optional[Union[str, _models.OwnerCopyMode]] = None, + copy_file_smb_info: Optional[_models.CopyFileSmbInfo] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Copies a blob or file to a destination file within the storage account. + + :param copy_source: Specifies the URL of the source file or blob, up to 2 KB in length. To copy + a file to another file within the same storage account, you may use Shared Key to authenticate + the source file. If you are copying a file from another storage account, or if you are copying + a blob from the same storage account or another storage account, then you must authenticate the + source file or blob using a shared access signature. If the source is a public blob, no + authentication is required to perform the copy operation. A file in a share snapshot can also + be specified as a copy source. Required. + :type copy_source: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param owner: Optional, NFS only. The owner of the file or directory. Default value is None. + :type owner: str + :param group: Optional, NFS only. The owning group of the file or directory. Default value is + None. + :type group: str + :param file_mode: Optional, NFS only. The file mode of the file or directory. Default value is + None. + :type file_mode: str + :param file_mode_copy_mode: NFS only. Applicable only when the copy source is a File. + Determines the copy behavior of the mode bits of the file. source: The mode on the destination + file is copied from the source file. override: The mode on the destination file is determined + via the x-ms-mode header. Known values are: "source" and "override". Default value is None. + :type file_mode_copy_mode: str or ~azure.storage.fileshare.models.ModeCopyMode + :param file_owner_copy_mode: NFS only. Determines the copy behavior of the owner user + identifier (UID) and group identifier (GID) of the file. source: The owner user identifier + (UID) and group identifier (GID) on the destination file is copied from the source file. + override: The owner user identifier (UID) and group identifier (GID) on the destination file is + determined via the x-ms-owner and x-ms-group headers. Known values are: "source" and + "override". Default value is None. + :type file_owner_copy_mode: str or ~azure.storage.fileshare.models.OwnerCopyMode + :param copy_file_smb_info: Parameter group. Default value is None. + :type copy_file_smb_info: ~azure.storage.fileshare.models.CopyFileSmbInfo + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = kwargs.pop("params", {}) or {} + + cls: ClsType[None] = kwargs.pop("cls", None) + + _file_permission_copy_mode = None + _ignore_read_only = None + _file_attributes = None + _file_creation_time = None + _file_last_write_time = None + _file_change_time = None + _set_archive_attribute = None + _lease_id = None + if copy_file_smb_info is not None: + _file_attributes = copy_file_smb_info.file_attributes + _file_change_time = copy_file_smb_info.file_change_time + _file_creation_time = copy_file_smb_info.file_creation_time + _file_last_write_time = copy_file_smb_info.file_last_write_time + _file_permission_copy_mode = copy_file_smb_info.file_permission_copy_mode + _ignore_read_only = copy_file_smb_info.ignore_read_only + _set_archive_attribute = copy_file_smb_info.set_archive_attribute + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_start_copy_request( + url=self._config.url, + copy_source=copy_source, + timeout=timeout, + metadata=metadata, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + file_permission_copy_mode=_file_permission_copy_mode, + ignore_read_only=_ignore_read_only, + file_attributes=_file_attributes, + file_creation_time=_file_creation_time, + file_last_write_time=_file_last_write_time, + file_change_time=_file_change_time, + set_archive_attribute=_set_archive_attribute, + lease_id=_lease_id, + owner=owner, + group=group, + file_mode=file_mode, + file_mode_copy_mode=file_mode_copy_mode, + file_owner_copy_mode=file_owner_copy_mode, + allow_trailing_dot=self._config.allow_trailing_dot, + allow_source_trailing_dot=self._config.allow_source_trailing_dot, + file_request_intent=self._config.file_request_intent, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-copy-id"] = self._deserialize("str", response.headers.get("x-ms-copy-id")) + response_headers["x-ms-copy-status"] = self._deserialize("str", response.headers.get("x-ms-copy-status")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def abort_copy( # pylint: disable=inconsistent-return-statements + self, + copy_id: str, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Aborts a pending Copy File operation, and leaves a destination file with zero length and full + metadata. + + :param copy_id: The copy identifier provided in the x-ms-copy-id header of the original Copy + File operation. Required. + :type copy_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["copy"] = kwargs.pop("comp", _params.pop("comp", "copy")) + copy_action_abort_constant: Literal["abort"] = kwargs.pop( + "copy_action_abort_constant", _headers.pop("x-ms-copy-action", "abort") + ) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_abort_copy_request( + url=self._config.url, + copy_id=copy_id, + timeout=timeout, + lease_id=_lease_id, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + copy_action_abort_constant=copy_action_abort_constant, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [204]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def list_handles( + self, + marker: Optional[str] = None, + maxresults: Optional[int] = None, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + **kwargs: Any + ) -> _models.ListHandlesResponse: + # pylint: disable=line-too-long + """Lists handles for file. + + :param marker: A string value that identifies the portion of the list to be returned with the + next list operation. The operation returns a marker value within the response body if the list + returned was not complete. The marker value may then be used in a subsequent call to request + the next set of list items. The marker value is opaque to the client. Default value is None. + :type marker: str + :param maxresults: Specifies the maximum number of entries to return. If the request does not + specify maxresults, or specifies a value greater than 5,000, the server will return up to 5,000 + items. Default value is None. + :type maxresults: int + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :return: ListHandlesResponse or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.ListHandlesResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["listhandles"] = kwargs.pop("comp", _params.pop("comp", "listhandles")) + cls: ClsType[_models.ListHandlesResponse] = kwargs.pop("cls", None) + + _request = build_list_handles_request( + url=self._config.url, + marker=marker, + maxresults=maxresults, + timeout=timeout, + sharesnapshot=sharesnapshot, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["Content-Type"] = self._deserialize("str", response.headers.get("Content-Type")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("ListHandlesResponse", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def force_close_handles( # pylint: disable=inconsistent-return-statements + self, + handle_id: str, + timeout: Optional[int] = None, + marker: Optional[str] = None, + sharesnapshot: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Closes all handles open for given file. + + :param handle_id: Specifies handle ID opened on the file or directory to be closed. Asterisk + (‘*’) is a wildcard that specifies all handles. Required. + :type handle_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param marker: A string value that identifies the portion of the list to be returned with the + next list operation. The operation returns a marker value within the response body if the list + returned was not complete. The marker value may then be used in a subsequent call to request + the next set of list items. The marker value is opaque to the client. Default value is None. + :type marker: str + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["forceclosehandles"] = kwargs.pop("comp", _params.pop("comp", "forceclosehandles")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_force_close_handles_request( + url=self._config.url, + handle_id=handle_id, + timeout=timeout, + marker=marker, + sharesnapshot=sharesnapshot, + allow_trailing_dot=self._config.allow_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-marker"] = self._deserialize("str", response.headers.get("x-ms-marker")) + response_headers["x-ms-number-of-handles-closed"] = self._deserialize( + "int", response.headers.get("x-ms-number-of-handles-closed") + ) + response_headers["x-ms-number-of-handles-failed"] = self._deserialize( + "int", response.headers.get("x-ms-number-of-handles-failed") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def rename( # pylint: disable=inconsistent-return-statements + self, + rename_source: str, + timeout: Optional[int] = None, + replace_if_exists: Optional[bool] = None, + ignore_read_only: Optional[bool] = None, + file_permission: str = "inherit", + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + file_permission_key: Optional[str] = None, + metadata: Optional[Dict[str, str]] = None, + source_lease_access_conditions: Optional[_models.SourceLeaseAccessConditions] = None, + destination_lease_access_conditions: Optional[_models.DestinationLeaseAccessConditions] = None, + copy_file_smb_info: Optional[_models.CopyFileSmbInfo] = None, + file_http_headers: Optional[_models.FileHTTPHeaders] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Renames a file. + + :param rename_source: Required. Specifies the URI-style path of the source file, up to 2 KB in + length. Required. + :type rename_source: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param replace_if_exists: Optional. A boolean value for if the destination file already exists, + whether this request will overwrite the file or not. If true, the rename will succeed and will + overwrite the destination file. If not provided or if false and the destination file does + exist, the request will not overwrite the destination file. If provided and the destination + file doesn’t exist, the rename will succeed. Note: This value does not override the + x-ms-file-copy-ignore-read-only header value. Default value is None. + :type replace_if_exists: bool + :param ignore_read_only: Optional. A boolean value that specifies whether the ReadOnly + attribute on a preexisting destination file should be respected. If true, the rename will + succeed, otherwise, a previous file at the destination with the ReadOnly attribute set will + cause the rename to fail. Default value is None. + :type ignore_read_only: bool + :param file_permission: If specified the permission (security descriptor) shall be set for the + directory/file. This header can be used if Permission size is <= 8KB, else + x-ms-file-permission-key header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. Default value is "inherit". + :type file_permission: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param file_permission_key: Key of the permission to be set for the directory/file. Note: Only + one of the x-ms-file-permission or x-ms-file-permission-key should be specified. Default value + is None. + :type file_permission_key: str + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param source_lease_access_conditions: Parameter group. Default value is None. + :type source_lease_access_conditions: + ~azure.storage.fileshare.models.SourceLeaseAccessConditions + :param destination_lease_access_conditions: Parameter group. Default value is None. + :type destination_lease_access_conditions: + ~azure.storage.fileshare.models.DestinationLeaseAccessConditions + :param copy_file_smb_info: Parameter group. Default value is None. + :type copy_file_smb_info: ~azure.storage.fileshare.models.CopyFileSmbInfo + :param file_http_headers: Parameter group. Default value is None. + :type file_http_headers: ~azure.storage.fileshare.models.FileHTTPHeaders + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["rename"] = kwargs.pop("comp", _params.pop("comp", "rename")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _source_lease_id = None + _destination_lease_id = None + _file_attributes = None + _file_creation_time = None + _file_last_write_time = None + _file_change_time = None + _file_content_type = None + if source_lease_access_conditions is not None: + _source_lease_id = source_lease_access_conditions.source_lease_id + if destination_lease_access_conditions is not None: + _destination_lease_id = destination_lease_access_conditions.destination_lease_id + if copy_file_smb_info is not None: + _file_attributes = copy_file_smb_info.file_attributes + _file_change_time = copy_file_smb_info.file_change_time + _file_creation_time = copy_file_smb_info.file_creation_time + _file_last_write_time = copy_file_smb_info.file_last_write_time + if file_http_headers is not None: + _file_content_type = file_http_headers.file_content_type + + _request = build_rename_request( + url=self._config.url, + rename_source=rename_source, + timeout=timeout, + replace_if_exists=replace_if_exists, + ignore_read_only=ignore_read_only, + source_lease_id=_source_lease_id, + destination_lease_id=_destination_lease_id, + file_attributes=_file_attributes, + file_creation_time=_file_creation_time, + file_last_write_time=_file_last_write_time, + file_change_time=_file_change_time, + file_permission=file_permission, + file_permission_format=file_permission_format, + file_permission_key=file_permission_key, + metadata=metadata, + file_content_type=_file_content_type, + allow_trailing_dot=self._config.allow_trailing_dot, + allow_source_trailing_dot=self._config.allow_source_trailing_dot, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-request-server-encrypted"] = self._deserialize( + "bool", response.headers.get("x-ms-request-server-encrypted") + ) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + response_headers["x-ms-file-attributes"] = self._deserialize( + "str", response.headers.get("x-ms-file-attributes") + ) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def create_symbolic_link( # pylint: disable=inconsistent-return-statements + self, + link_text: str, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + file_creation_time: str = "now", + file_last_write_time: str = "now", + request_id_parameter: Optional[str] = None, + owner: Optional[str] = None, + group: Optional[str] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Creates a symbolic link. + + :param link_text: NFS only. Required. The path to the original file, the symbolic link is + pointing to. The path is of type string which is not resolved and is stored as is. The path can + be absolute path or the relative path depending on the content stored in the symbolic link + file. Required. + :type link_text: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param file_creation_time: Creation time for the file/directory. Default value: Now. Default + value is "now". + :type file_creation_time: str + :param file_last_write_time: Last write time for the file/directory. Default value: Now. + Default value is "now". + :type file_last_write_time: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :param owner: Optional, NFS only. The owner of the file or directory. Default value is None. + :type owner: str + :param group: Optional, NFS only. The owning group of the file or directory. Default value is + None. + :type group: str + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["symboliclink"] = kwargs.pop("restype", _params.pop("restype", "symboliclink")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_create_symbolic_link_request( + url=self._config.url, + link_text=link_text, + timeout=timeout, + metadata=metadata, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + request_id_parameter=request_id_parameter, + lease_id=_lease_id, + owner=owner, + group=group, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-file-file-type"] = self._deserialize("str", response.headers.get("x-ms-file-file-type")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def get_symbolic_link( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """get_symbolic_link. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["symboliclink"] = kwargs.pop("restype", _params.pop("restype", "symboliclink")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_get_symbolic_link_request( + url=self._config.url, + timeout=timeout, + sharesnapshot=sharesnapshot, + request_id_parameter=request_id_parameter, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-link-text"] = self._deserialize("str", response.headers.get("x-ms-link-text")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def create_hard_link( # pylint: disable=inconsistent-return-statements + self, + target_file: str, + timeout: Optional[int] = None, + request_id_parameter: Optional[str] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Creates a hard link. + + :param target_file: NFS only. Required. Specifies the path of the target file to which the link + will be created, up to 2 KiB in length. It should be full path of the target from the root.The + target file must be in the same share and hence the same storage account. Required. + :type target_file: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["hardlink"] = kwargs.pop("restype", _params.pop("restype", "hardlink")) + file_type_constant: Literal["file"] = kwargs.pop("file_type_constant", _headers.pop("x-ms-type", "file")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_create_hard_link_request( + url=self._config.url, + target_file=target_file, + timeout=timeout, + request_id_parameter=request_id_parameter, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + file_type_constant=file_type_constant, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-file-creation-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-creation-time") + ) + response_headers["x-ms-file-last-write-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-last-write-time") + ) + response_headers["x-ms-file-change-time"] = self._deserialize( + "str", response.headers.get("x-ms-file-change-time") + ) + response_headers["x-ms-file-id"] = self._deserialize("str", response.headers.get("x-ms-file-id")) + response_headers["x-ms-file-parent-id"] = self._deserialize("str", response.headers.get("x-ms-file-parent-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-link-count"] = self._deserialize("int", response.headers.get("x-ms-link-count")) + response_headers["x-ms-mode"] = self._deserialize("str", response.headers.get("x-ms-mode")) + response_headers["x-ms-owner"] = self._deserialize("str", response.headers.get("x-ms-owner")) + response_headers["x-ms-group"] = self._deserialize("str", response.headers.get("x-ms-group")) + response_headers["x-ms-file-file-type"] = self._deserialize("str", response.headers.get("x-ms-file-file-type")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_patch.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_patch.py new file mode 100644 index 00000000..f7dd3251 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_patch.py @@ -0,0 +1,20 @@ +# ------------------------------------ +# Copyright (c) Microsoft Corporation. +# Licensed under the MIT License. +# ------------------------------------ +"""Customize generated code here. + +Follow our quickstart for examples: https://aka.ms/azsdk/python/dpcodegen/python/customize +""" +from typing import List + +__all__: List[str] = [] # Add all objects you want publicly available to users at this package level + + +def patch_sdk(): + """Do not remove from this file. + + `patch_sdk` is a last resort escape hatch that allows you to do customizations + you can't accomplish using the techniques described in + https://aka.ms/azsdk/python/dpcodegen/python/customize + """ diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_service_operations.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_service_operations.py new file mode 100644 index 00000000..57e5b246 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_service_operations.py @@ -0,0 +1,410 @@ +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +import sys +from typing import Any, Callable, Dict, List, Literal, Optional, TypeVar, Union + +from azure.core import PipelineClient +from azure.core.exceptions import ( + ClientAuthenticationError, + HttpResponseError, + ResourceExistsError, + ResourceNotFoundError, + ResourceNotModifiedError, + map_error, +) +from azure.core.pipeline import PipelineResponse +from azure.core.rest import HttpRequest, HttpResponse +from azure.core.tracing.decorator import distributed_trace +from azure.core.utils import case_insensitive_dict + +from .. import models as _models +from .._configuration import AzureFileStorageConfiguration +from .._serialization import Deserializer, Serializer + +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore +T = TypeVar("T") +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +_SERIALIZER = Serializer() +_SERIALIZER.client_side_validation = False + + +def build_set_properties_request( + url: str, + *, + content: Any, + timeout: Optional[int] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["service"] = kwargs.pop("restype", _params.pop("restype", "service")) + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, content=content, **kwargs) + + +def build_get_properties_request( + url: str, + *, + timeout: Optional[int] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["service"] = kwargs.pop("restype", _params.pop("restype", "service")) + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_list_shares_segment_request( + url: str, + *, + prefix: Optional[str] = None, + marker: Optional[str] = None, + maxresults: Optional[int] = None, + include: Optional[List[Union[str, _models.ListSharesIncludeType]]] = None, + timeout: Optional[int] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["list"] = kwargs.pop("comp", _params.pop("comp", "list")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if prefix is not None: + _params["prefix"] = _SERIALIZER.query("prefix", prefix, "str") + if marker is not None: + _params["marker"] = _SERIALIZER.query("marker", marker, "str") + if maxresults is not None: + _params["maxresults"] = _SERIALIZER.query("maxresults", maxresults, "int", minimum=1) + if include is not None: + _params["include"] = _SERIALIZER.query("include", include, "[str]", div=",") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +class ServiceOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.storage.fileshare.AzureFileStorage`'s + :attr:`service` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs): + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AzureFileStorageConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace + def set_properties( # pylint: disable=inconsistent-return-statements + self, storage_service_properties: _models.StorageServiceProperties, timeout: Optional[int] = None, **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Sets properties for a storage account's File service endpoint, including properties for Storage + Analytics metrics and CORS (Cross-Origin Resource Sharing) rules. + + :param storage_service_properties: The StorageService properties. Required. + :type storage_service_properties: ~azure.storage.fileshare.models.StorageServiceProperties + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["service"] = kwargs.pop("restype", _params.pop("restype", "service")) + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/xml")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _content = self._serialize.body(storage_service_properties, "StorageServiceProperties", is_xml=True) + + _request = build_set_properties_request( + url=self._config.url, + timeout=timeout, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + content_type=content_type, + version=self._config.version, + content=_content, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def get_properties(self, timeout: Optional[int] = None, **kwargs: Any) -> _models.StorageServiceProperties: + # pylint: disable=line-too-long + """Gets the properties of a storage account's File service, including properties for Storage + Analytics metrics and CORS (Cross-Origin Resource Sharing) rules. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: StorageServiceProperties or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.StorageServiceProperties + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["service"] = kwargs.pop("restype", _params.pop("restype", "service")) + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + cls: ClsType[_models.StorageServiceProperties] = kwargs.pop("cls", None) + + _request = build_get_properties_request( + url=self._config.url, + timeout=timeout, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + + deserialized = self._deserialize("StorageServiceProperties", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def list_shares_segment( + self, + prefix: Optional[str] = None, + marker: Optional[str] = None, + maxresults: Optional[int] = None, + include: Optional[List[Union[str, _models.ListSharesIncludeType]]] = None, + timeout: Optional[int] = None, + **kwargs: Any + ) -> _models.ListSharesResponse: + # pylint: disable=line-too-long + """The List Shares Segment operation returns a list of the shares and share snapshots under the + specified account. + + :param prefix: Filters the results to return only entries whose name begins with the specified + prefix. Default value is None. + :type prefix: str + :param marker: A string value that identifies the portion of the list to be returned with the + next list operation. The operation returns a marker value within the response body if the list + returned was not complete. The marker value may then be used in a subsequent call to request + the next set of list items. The marker value is opaque to the client. Default value is None. + :type marker: str + :param maxresults: Specifies the maximum number of entries to return. If the request does not + specify maxresults, or specifies a value greater than 5,000, the server will return up to 5,000 + items. Default value is None. + :type maxresults: int + :param include: Include this parameter to specify one or more datasets to include in the + response. Default value is None. + :type include: list[str or ~azure.storage.fileshare.models.ListSharesIncludeType] + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: ListSharesResponse or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.ListSharesResponse + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["list"] = kwargs.pop("comp", _params.pop("comp", "list")) + cls: ClsType[_models.ListSharesResponse] = kwargs.pop("cls", None) + + _request = build_list_shares_segment_request( + url=self._config.url, + prefix=prefix, + marker=marker, + maxresults=maxresults, + include=include, + timeout=timeout, + file_request_intent=self._config.file_request_intent, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + + deserialized = self._deserialize("ListSharesResponse", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_share_operations.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_share_operations.py new file mode 100644 index 00000000..920a64e2 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/operations/_share_operations.py @@ -0,0 +1,2595 @@ +# pylint: disable=too-many-lines +# coding=utf-8 +# -------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for license information. +# Code generated by Microsoft (R) AutoRest Code Generator. +# Changes may cause incorrect behavior and will be lost if the code is regenerated. +# -------------------------------------------------------------------------- +from io import IOBase +import sys +from typing import Any, Callable, Dict, IO, List, Literal, Optional, TypeVar, Union, overload + +from azure.core import PipelineClient +from azure.core.exceptions import ( + ClientAuthenticationError, + HttpResponseError, + ResourceExistsError, + ResourceNotFoundError, + ResourceNotModifiedError, + map_error, +) +from azure.core.pipeline import PipelineResponse +from azure.core.rest import HttpRequest, HttpResponse +from azure.core.tracing.decorator import distributed_trace +from azure.core.utils import case_insensitive_dict + +from .. import models as _models +from .._configuration import AzureFileStorageConfiguration +from .._serialization import Deserializer, Serializer + +if sys.version_info >= (3, 9): + from collections.abc import MutableMapping +else: + from typing import MutableMapping # type: ignore +T = TypeVar("T") +ClsType = Optional[Callable[[PipelineResponse[HttpRequest, HttpResponse], T, Dict[str, Any]], Any]] + +_SERIALIZER = Serializer() +_SERIALIZER.client_side_validation = False + + +def build_create_request( + url: str, + *, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + quota: Optional[int] = None, + access_tier: Optional[Union[str, _models.ShareAccessTier]] = None, + enabled_protocols: Optional[str] = None, + root_squash: Optional[Union[str, _models.ShareRootSquash]] = None, + enable_snapshot_virtual_directory_access: Optional[bool] = None, + paid_bursting_enabled: Optional[bool] = None, + paid_bursting_max_bandwidth_mibps: Optional[int] = None, + paid_bursting_max_iops: Optional[int] = None, + share_provisioned_iops: Optional[int] = None, + share_provisioned_bandwidth_mibps: Optional[int] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + if metadata is not None: + _headers["x-ms-meta"] = _SERIALIZER.header("metadata", metadata, "{str}") + if quota is not None: + _headers["x-ms-share-quota"] = _SERIALIZER.header("quota", quota, "int", minimum=1) + if access_tier is not None: + _headers["x-ms-access-tier"] = _SERIALIZER.header("access_tier", access_tier, "str") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if enabled_protocols is not None: + _headers["x-ms-enabled-protocols"] = _SERIALIZER.header("enabled_protocols", enabled_protocols, "str") + if root_squash is not None: + _headers["x-ms-root-squash"] = _SERIALIZER.header("root_squash", root_squash, "str") + if enable_snapshot_virtual_directory_access is not None: + _headers["x-ms-enable-snapshot-virtual-directory-access"] = _SERIALIZER.header( + "enable_snapshot_virtual_directory_access", enable_snapshot_virtual_directory_access, "bool" + ) + if paid_bursting_enabled is not None: + _headers["x-ms-share-paid-bursting-enabled"] = _SERIALIZER.header( + "paid_bursting_enabled", paid_bursting_enabled, "bool" + ) + if paid_bursting_max_bandwidth_mibps is not None: + _headers["x-ms-share-paid-bursting-max-bandwidth-mibps"] = _SERIALIZER.header( + "paid_bursting_max_bandwidth_mibps", paid_bursting_max_bandwidth_mibps, "int" + ) + if paid_bursting_max_iops is not None: + _headers["x-ms-share-paid-bursting-max-iops"] = _SERIALIZER.header( + "paid_bursting_max_iops", paid_bursting_max_iops, "int" + ) + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + if share_provisioned_iops is not None: + _headers["x-ms-share-provisioned-iops"] = _SERIALIZER.header( + "share_provisioned_iops", share_provisioned_iops, "int" + ) + if share_provisioned_bandwidth_mibps is not None: + _headers["x-ms-share-provisioned-bandwidth-mibps"] = _SERIALIZER.header( + "share_provisioned_bandwidth_mibps", share_provisioned_bandwidth_mibps, "int" + ) + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_get_properties_request( + url: str, + *, + sharesnapshot: Optional[str] = None, + timeout: Optional[int] = None, + lease_id: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_delete_request( + url: str, + *, + sharesnapshot: Optional[str] = None, + timeout: Optional[int] = None, + delete_snapshots: Optional[Union[str, _models.DeleteSnapshotsOptionType]] = None, + lease_id: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if delete_snapshots is not None: + _headers["x-ms-delete-snapshots"] = _SERIALIZER.header("delete_snapshots", delete_snapshots, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="DELETE", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_acquire_lease_request( + url: str, + *, + timeout: Optional[int] = None, + duration: Optional[int] = None, + proposed_lease_id: Optional[str] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["acquire"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "acquire")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + + # Construct headers + _headers["x-ms-lease-action"] = _SERIALIZER.header("action", action, "str") + if duration is not None: + _headers["x-ms-lease-duration"] = _SERIALIZER.header("duration", duration, "int") + if proposed_lease_id is not None: + _headers["x-ms-proposed-lease-id"] = _SERIALIZER.header("proposed_lease_id", proposed_lease_id, "str") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if request_id_parameter is not None: + _headers["x-ms-client-request-id"] = _SERIALIZER.header("request_id_parameter", request_id_parameter, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_release_lease_request( + url: str, + *, + lease_id: str, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["release"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "release")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + + # Construct headers + _headers["x-ms-lease-action"] = _SERIALIZER.header("action", action, "str") + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if request_id_parameter is not None: + _headers["x-ms-client-request-id"] = _SERIALIZER.header("request_id_parameter", request_id_parameter, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_change_lease_request( + url: str, + *, + lease_id: str, + timeout: Optional[int] = None, + proposed_lease_id: Optional[str] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["change"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "change")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + + # Construct headers + _headers["x-ms-lease-action"] = _SERIALIZER.header("action", action, "str") + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if proposed_lease_id is not None: + _headers["x-ms-proposed-lease-id"] = _SERIALIZER.header("proposed_lease_id", proposed_lease_id, "str") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if request_id_parameter is not None: + _headers["x-ms-client-request-id"] = _SERIALIZER.header("request_id_parameter", request_id_parameter, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_renew_lease_request( + url: str, + *, + lease_id: str, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["renew"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "renew")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + + # Construct headers + _headers["x-ms-lease-action"] = _SERIALIZER.header("action", action, "str") + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if request_id_parameter is not None: + _headers["x-ms-client-request-id"] = _SERIALIZER.header("request_id_parameter", request_id_parameter, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_break_lease_request( + url: str, + *, + timeout: Optional[int] = None, + break_period: Optional[int] = None, + lease_id: Optional[str] = None, + request_id_parameter: Optional[str] = None, + sharesnapshot: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["break"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "break")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + if sharesnapshot is not None: + _params["sharesnapshot"] = _SERIALIZER.query("sharesnapshot", sharesnapshot, "str") + + # Construct headers + _headers["x-ms-lease-action"] = _SERIALIZER.header("action", action, "str") + if break_period is not None: + _headers["x-ms-lease-break-period"] = _SERIALIZER.header("break_period", break_period, "int") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if request_id_parameter is not None: + _headers["x-ms-client-request-id"] = _SERIALIZER.header("request_id_parameter", request_id_parameter, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_create_snapshot_request( + url: str, + *, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["snapshot"] = kwargs.pop("comp", _params.pop("comp", "snapshot")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + if metadata is not None: + _headers["x-ms-meta"] = _SERIALIZER.header("metadata", metadata, "{str}") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_create_permission_request( + url: str, + *, + timeout: Optional[int] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["filepermission"] = kwargs.pop("comp", _params.pop("comp", "filepermission")) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_get_permission_request( + url: str, + *, + file_permission_key: str, + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + timeout: Optional[int] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["filepermission"] = kwargs.pop("comp", _params.pop("comp", "filepermission")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/json") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-file-permission-key"] = _SERIALIZER.header("file_permission_key", file_permission_key, "str") + if file_permission_format is not None: + _headers["x-ms-file-permission-format"] = _SERIALIZER.header( + "file_permission_format", file_permission_format, "str" + ) + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_set_properties_request( + url: str, + *, + timeout: Optional[int] = None, + quota: Optional[int] = None, + access_tier: Optional[Union[str, _models.ShareAccessTier]] = None, + lease_id: Optional[str] = None, + root_squash: Optional[Union[str, _models.ShareRootSquash]] = None, + enable_snapshot_virtual_directory_access: Optional[bool] = None, + paid_bursting_enabled: Optional[bool] = None, + paid_bursting_max_bandwidth_mibps: Optional[int] = None, + paid_bursting_max_iops: Optional[int] = None, + share_provisioned_iops: Optional[int] = None, + share_provisioned_bandwidth_mibps: Optional[int] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if quota is not None: + _headers["x-ms-share-quota"] = _SERIALIZER.header("quota", quota, "int", minimum=1) + if access_tier is not None: + _headers["x-ms-access-tier"] = _SERIALIZER.header("access_tier", access_tier, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if root_squash is not None: + _headers["x-ms-root-squash"] = _SERIALIZER.header("root_squash", root_squash, "str") + if enable_snapshot_virtual_directory_access is not None: + _headers["x-ms-enable-snapshot-virtual-directory-access"] = _SERIALIZER.header( + "enable_snapshot_virtual_directory_access", enable_snapshot_virtual_directory_access, "bool" + ) + if paid_bursting_enabled is not None: + _headers["x-ms-share-paid-bursting-enabled"] = _SERIALIZER.header( + "paid_bursting_enabled", paid_bursting_enabled, "bool" + ) + if paid_bursting_max_bandwidth_mibps is not None: + _headers["x-ms-share-paid-bursting-max-bandwidth-mibps"] = _SERIALIZER.header( + "paid_bursting_max_bandwidth_mibps", paid_bursting_max_bandwidth_mibps, "int" + ) + if paid_bursting_max_iops is not None: + _headers["x-ms-share-paid-bursting-max-iops"] = _SERIALIZER.header( + "paid_bursting_max_iops", paid_bursting_max_iops, "int" + ) + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + if share_provisioned_iops is not None: + _headers["x-ms-share-provisioned-iops"] = _SERIALIZER.header( + "share_provisioned_iops", share_provisioned_iops, "int" + ) + if share_provisioned_bandwidth_mibps is not None: + _headers["x-ms-share-provisioned-bandwidth-mibps"] = _SERIALIZER.header( + "share_provisioned_bandwidth_mibps", share_provisioned_bandwidth_mibps, "int" + ) + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_set_metadata_request( + url: str, + *, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + lease_id: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["metadata"] = kwargs.pop("comp", _params.pop("comp", "metadata")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + if metadata is not None: + _headers["x-ms-meta"] = _SERIALIZER.header("metadata", metadata, "{str}") + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_get_access_policy_request( + url: str, + *, + timeout: Optional[int] = None, + lease_id: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["acl"] = kwargs.pop("comp", _params.pop("comp", "acl")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_set_access_policy_request( + url: str, + *, + timeout: Optional[int] = None, + lease_id: Optional[str] = None, + content: Any = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["acl"] = kwargs.pop("comp", _params.pop("comp", "acl")) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + if content_type is not None: + _headers["Content-Type"] = _SERIALIZER.header("content_type", content_type, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, content=content, **kwargs) + + +def build_get_statistics_request( + url: str, + *, + timeout: Optional[int] = None, + lease_id: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["stats"] = kwargs.pop("comp", _params.pop("comp", "stats")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if lease_id is not None: + _headers["x-ms-lease-id"] = _SERIALIZER.header("lease_id", lease_id, "str") + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="GET", url=_url, params=_params, headers=_headers, **kwargs) + + +def build_restore_request( + url: str, + *, + timeout: Optional[int] = None, + request_id_parameter: Optional[str] = None, + deleted_share_name: Optional[str] = None, + deleted_share_version: Optional[str] = None, + file_request_intent: Optional[Union[str, _models.ShareTokenIntent]] = None, + **kwargs: Any +) -> HttpRequest: + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["undelete"] = kwargs.pop("comp", _params.pop("comp", "undelete")) + version: Literal["2025-05-05"] = kwargs.pop("version", _headers.pop("x-ms-version", "2025-05-05")) + accept = _headers.pop("Accept", "application/xml") + + # Construct URL + _url = kwargs.pop("template_url", "{url}") + path_format_arguments = { + "url": _SERIALIZER.url("url", url, "str", skip_quote=True), + } + + _url: str = _url.format(**path_format_arguments) # type: ignore + + # Construct parameters + _params["restype"] = _SERIALIZER.query("restype", restype, "str") + _params["comp"] = _SERIALIZER.query("comp", comp, "str") + if timeout is not None: + _params["timeout"] = _SERIALIZER.query("timeout", timeout, "int", minimum=0) + + # Construct headers + _headers["x-ms-version"] = _SERIALIZER.header("version", version, "str") + if request_id_parameter is not None: + _headers["x-ms-client-request-id"] = _SERIALIZER.header("request_id_parameter", request_id_parameter, "str") + if deleted_share_name is not None: + _headers["x-ms-deleted-share-name"] = _SERIALIZER.header("deleted_share_name", deleted_share_name, "str") + if deleted_share_version is not None: + _headers["x-ms-deleted-share-version"] = _SERIALIZER.header( + "deleted_share_version", deleted_share_version, "str" + ) + if file_request_intent is not None: + _headers["x-ms-file-request-intent"] = _SERIALIZER.header("file_request_intent", file_request_intent, "str") + _headers["Accept"] = _SERIALIZER.header("accept", accept, "str") + + return HttpRequest(method="PUT", url=_url, params=_params, headers=_headers, **kwargs) + + +class ShareOperations: + """ + .. warning:: + **DO NOT** instantiate this class directly. + + Instead, you should access the following operations through + :class:`~azure.storage.fileshare.AzureFileStorage`'s + :attr:`share` attribute. + """ + + models = _models + + def __init__(self, *args, **kwargs): + input_args = list(args) + self._client: PipelineClient = input_args.pop(0) if input_args else kwargs.pop("client") + self._config: AzureFileStorageConfiguration = input_args.pop(0) if input_args else kwargs.pop("config") + self._serialize: Serializer = input_args.pop(0) if input_args else kwargs.pop("serializer") + self._deserialize: Deserializer = input_args.pop(0) if input_args else kwargs.pop("deserializer") + + @distributed_trace + def create( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + quota: Optional[int] = None, + access_tier: Optional[Union[str, _models.ShareAccessTier]] = None, + enabled_protocols: Optional[str] = None, + root_squash: Optional[Union[str, _models.ShareRootSquash]] = None, + enable_snapshot_virtual_directory_access: Optional[bool] = None, + paid_bursting_enabled: Optional[bool] = None, + paid_bursting_max_bandwidth_mibps: Optional[int] = None, + paid_bursting_max_iops: Optional[int] = None, + share_provisioned_iops: Optional[int] = None, + share_provisioned_bandwidth_mibps: Optional[int] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Creates a new share under the specified account. If the share with the same name already + exists, the operation fails. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param quota: Specifies the maximum size of the share, in gigabytes. Default value is None. + :type quota: int + :param access_tier: Specifies the access tier of the share. Known values are: + "TransactionOptimized", "Hot", "Cool", and "Premium". Default value is None. + :type access_tier: str or ~azure.storage.fileshare.models.ShareAccessTier + :param enabled_protocols: Protocols to enable on the share. Default value is None. + :type enabled_protocols: str + :param root_squash: Root squash to set on the share. Only valid for NFS shares. Known values + are: "NoRootSquash", "RootSquash", and "AllSquash". Default value is None. + :type root_squash: str or ~azure.storage.fileshare.models.ShareRootSquash + :param enable_snapshot_virtual_directory_access: Default value is None. + :type enable_snapshot_virtual_directory_access: bool + :param paid_bursting_enabled: Optional. Boolean. Default if not specified is false. This + property enables paid bursting. Default value is None. + :type paid_bursting_enabled: bool + :param paid_bursting_max_bandwidth_mibps: Optional. Integer. Default if not specified is the + maximum throughput the file share can support. Current maximum for a file share is 10,340 + MiB/sec. Default value is None. + :type paid_bursting_max_bandwidth_mibps: int + :param paid_bursting_max_iops: Optional. Integer. Default if not specified is the maximum IOPS + the file share can support. Current maximum for a file share is 102,400 IOPS. Default value is + None. + :type paid_bursting_max_iops: int + :param share_provisioned_iops: Optional. Supported in version 2025-01-05 and later. Only + allowed for provisioned v2 file shares. Specifies the provisioned number of input/output + operations per second (IOPS) of the share. If this is not specified, the provisioned IOPS is + set to value calculated based on recommendation formula. Default value is None. + :type share_provisioned_iops: int + :param share_provisioned_bandwidth_mibps: Optional. Supported in version 2025-01-05 and later. + Only allowed for provisioned v2 file shares. Specifies the provisioned bandwidth of the share, + in mebibytes per second (MiBps). If this is not specified, the provisioned bandwidth is set to + value calculated based on recommendation formula. Default value is None. + :type share_provisioned_bandwidth_mibps: int + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_create_request( + url=self._config.url, + timeout=timeout, + metadata=metadata, + quota=quota, + access_tier=access_tier, + enabled_protocols=enabled_protocols, + root_squash=root_squash, + enable_snapshot_virtual_directory_access=enable_snapshot_virtual_directory_access, + paid_bursting_enabled=paid_bursting_enabled, + paid_bursting_max_bandwidth_mibps=paid_bursting_max_bandwidth_mibps, + paid_bursting_max_iops=paid_bursting_max_iops, + share_provisioned_iops=share_provisioned_iops, + share_provisioned_bandwidth_mibps=share_provisioned_bandwidth_mibps, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-share-quota"] = self._deserialize("int", response.headers.get("x-ms-share-quota")) + response_headers["x-ms-share-provisioned-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-iops") + ) + response_headers["x-ms-share-provisioned-bandwidth-mibps"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-bandwidth-mibps") + ) + response_headers["x-ms-share-included-burst-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-included-burst-iops") + ) + response_headers["x-ms-share-max-burst-credits-for-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-max-burst-credits-for-iops") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def get_properties( # pylint: disable=inconsistent-return-statements + self, + sharesnapshot: Optional[str] = None, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Returns all user-defined metadata and system properties for the specified share or share + snapshot. The data returned does not include the share's list of files. + + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_get_properties_request( + url=self._config.url, + sharesnapshot=sharesnapshot, + timeout=timeout, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-meta"] = self._deserialize("{str}", response.headers.get("x-ms-meta")) + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-share-quota"] = self._deserialize("int", response.headers.get("x-ms-share-quota")) + response_headers["x-ms-share-provisioned-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-iops") + ) + response_headers["x-ms-share-provisioned-ingress-mbps"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-ingress-mbps") + ) + response_headers["x-ms-share-provisioned-egress-mbps"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-egress-mbps") + ) + response_headers["x-ms-share-next-allowed-quota-downgrade-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-share-next-allowed-quota-downgrade-time") + ) + response_headers["x-ms-share-provisioned-bandwidth-mibps"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-bandwidth-mibps") + ) + response_headers["x-ms-lease-duration"] = self._deserialize("str", response.headers.get("x-ms-lease-duration")) + response_headers["x-ms-lease-state"] = self._deserialize("str", response.headers.get("x-ms-lease-state")) + response_headers["x-ms-lease-status"] = self._deserialize("str", response.headers.get("x-ms-lease-status")) + response_headers["x-ms-access-tier"] = self._deserialize("str", response.headers.get("x-ms-access-tier")) + response_headers["x-ms-access-tier-change-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-access-tier-change-time") + ) + response_headers["x-ms-access-tier-transition-state"] = self._deserialize( + "str", response.headers.get("x-ms-access-tier-transition-state") + ) + response_headers["x-ms-enabled-protocols"] = self._deserialize( + "str", response.headers.get("x-ms-enabled-protocols") + ) + response_headers["x-ms-root-squash"] = self._deserialize("str", response.headers.get("x-ms-root-squash")) + response_headers["x-ms-enable-snapshot-virtual-directory-access"] = self._deserialize( + "bool", response.headers.get("x-ms-enable-snapshot-virtual-directory-access") + ) + response_headers["x-ms-share-paid-bursting-enabled"] = self._deserialize( + "bool", response.headers.get("x-ms-share-paid-bursting-enabled") + ) + response_headers["x-ms-share-paid-bursting-max-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-paid-bursting-max-iops") + ) + response_headers["x-ms-share-paid-bursting-max-bandwidth-mibps"] = self._deserialize( + "int", response.headers.get("x-ms-share-paid-bursting-max-bandwidth-mibps") + ) + response_headers["x-ms-share-included-burst-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-included-burst-iops") + ) + response_headers["x-ms-share-max-burst-credits-for-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-max-burst-credits-for-iops") + ) + response_headers["x-ms-share-next-allowed-provisioned-iops-downgrade-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-share-next-allowed-provisioned-iops-downgrade-time") + ) + response_headers["x-ms-share-next-allowed-provisioned-bandwidth-downgrade-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-share-next-allowed-provisioned-bandwidth-downgrade-time") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def delete( # pylint: disable=inconsistent-return-statements + self, + sharesnapshot: Optional[str] = None, + timeout: Optional[int] = None, + delete_snapshots: Optional[Union[str, _models.DeleteSnapshotsOptionType]] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Operation marks the specified share or share snapshot for deletion. The share or share snapshot + and any files contained within it are later deleted during garbage collection. + + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param delete_snapshots: Specifies the option include to delete the base share and all of its + snapshots. Known values are: "include" and "include-leased". Default value is None. + :type delete_snapshots: str or ~azure.storage.fileshare.models.DeleteSnapshotsOptionType + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_delete_request( + url=self._config.url, + sharesnapshot=sharesnapshot, + timeout=timeout, + delete_snapshots=delete_snapshots, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-file-share-usage-bytes"] = self._deserialize( + "int", response.headers.get("x-ms-file-share-usage-bytes") + ) + response_headers["x-ms-file-share-snapshot-usage-bytes"] = self._deserialize( + "int", response.headers.get("x-ms-file-share-snapshot-usage-bytes") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def acquire_lease( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + duration: Optional[int] = None, + proposed_lease_id: Optional[str] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """The Lease Share operation establishes and manages a lock on a share, or the specified snapshot + for set and delete share operations. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param duration: Specifies the duration of the lease, in seconds, or negative one (-1) for a + lease that never expires. A non-infinite lease can be between 15 and 60 seconds. A lease + duration cannot be changed using renew or change. Default value is None. + :type duration: int + :param proposed_lease_id: Proposed lease ID, in a GUID string format. The File service returns + 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid + Constructor (String) for a list of valid GUID string formats. Default value is None. + :type proposed_lease_id: str + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["acquire"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "acquire")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_acquire_lease_request( + url=self._config.url, + timeout=timeout, + duration=duration, + proposed_lease_id=proposed_lease_id, + sharesnapshot=sharesnapshot, + request_id_parameter=request_id_parameter, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def release_lease( # pylint: disable=inconsistent-return-statements + self, + lease_id: str, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """The Lease Share operation establishes and manages a lock on a share, or the specified snapshot + for set and delete share operations. + + :param lease_id: Specifies the current lease ID on the resource. Required. + :type lease_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["release"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "release")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_release_lease_request( + url=self._config.url, + lease_id=lease_id, + timeout=timeout, + sharesnapshot=sharesnapshot, + request_id_parameter=request_id_parameter, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def change_lease( # pylint: disable=inconsistent-return-statements + self, + lease_id: str, + timeout: Optional[int] = None, + proposed_lease_id: Optional[str] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """The Lease Share operation establishes and manages a lock on a share, or the specified snapshot + for set and delete share operations. + + :param lease_id: Specifies the current lease ID on the resource. Required. + :type lease_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param proposed_lease_id: Proposed lease ID, in a GUID string format. The File service returns + 400 (Invalid request) if the proposed lease ID is not in the correct format. See Guid + Constructor (String) for a list of valid GUID string formats. Default value is None. + :type proposed_lease_id: str + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["change"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "change")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_change_lease_request( + url=self._config.url, + lease_id=lease_id, + timeout=timeout, + proposed_lease_id=proposed_lease_id, + sharesnapshot=sharesnapshot, + request_id_parameter=request_id_parameter, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def renew_lease( # pylint: disable=inconsistent-return-statements + self, + lease_id: str, + timeout: Optional[int] = None, + sharesnapshot: Optional[str] = None, + request_id_parameter: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """The Lease Share operation establishes and manages a lock on a share, or the specified snapshot + for set and delete share operations. + + :param lease_id: Specifies the current lease ID on the resource. Required. + :type lease_id: str + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["renew"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "renew")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_renew_lease_request( + url=self._config.url, + lease_id=lease_id, + timeout=timeout, + sharesnapshot=sharesnapshot, + request_id_parameter=request_id_parameter, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def break_lease( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + break_period: Optional[int] = None, + request_id_parameter: Optional[str] = None, + sharesnapshot: Optional[str] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """The Lease Share operation establishes and manages a lock on a share, or the specified snapshot + for set and delete share operations. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param break_period: For a break operation, proposed duration the lease should continue before + it is broken, in seconds, between 0 and 60. This break period is only used if it is shorter + than the time remaining on the lease. If longer, the time remaining on the lease is used. A new + lease will not be available before the break period has expired, but the lease may be held for + longer than the break period. If this header does not appear with a break operation, a + fixed-duration lease breaks after the remaining lease period elapses, and an infinite lease + breaks immediately. Default value is None. + :type break_period: int + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :param sharesnapshot: The snapshot parameter is an opaque DateTime value that, when present, + specifies the share snapshot to query. Default value is None. + :type sharesnapshot: str + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + comp: Literal["lease"] = kwargs.pop("comp", _params.pop("comp", "lease")) + action: Literal["break"] = kwargs.pop("action", _headers.pop("x-ms-lease-action", "break")) + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_break_lease_request( + url=self._config.url, + timeout=timeout, + break_period=break_period, + lease_id=_lease_id, + request_id_parameter=request_id_parameter, + sharesnapshot=sharesnapshot, + file_request_intent=self._config.file_request_intent, + comp=comp, + action=action, + restype=restype, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [202]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-lease-time"] = self._deserialize("int", response.headers.get("x-ms-lease-time")) + response_headers["x-ms-lease-id"] = self._deserialize("str", response.headers.get("x-ms-lease-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def create_snapshot( # pylint: disable=inconsistent-return-statements + self, timeout: Optional[int] = None, metadata: Optional[Dict[str, str]] = None, **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Creates a read-only snapshot of a share. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["snapshot"] = kwargs.pop("comp", _params.pop("comp", "snapshot")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_create_snapshot_request( + url=self._config.url, + timeout=timeout, + metadata=metadata, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-snapshot"] = self._deserialize("str", response.headers.get("x-ms-snapshot")) + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @overload + def create_permission( + self, + share_permission: _models.SharePermission, + timeout: Optional[int] = None, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Create a permission (a security descriptor). + + :param share_permission: A permission (a security descriptor) at the share level. Required. + :type share_permission: ~azure.storage.fileshare.models.SharePermission + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :keyword content_type: Body Parameter content-type. Content type parameter for JSON body. + Default value is "application/json". + :paramtype content_type: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @overload + def create_permission( + self, + share_permission: IO[bytes], + timeout: Optional[int] = None, + *, + content_type: str = "application/json", + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Create a permission (a security descriptor). + + :param share_permission: A permission (a security descriptor) at the share level. Required. + :type share_permission: IO[bytes] + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :keyword content_type: Body Parameter content-type. Content type parameter for binary body. + Default value is "application/json". + :paramtype content_type: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + + @distributed_trace + def create_permission( # pylint: disable=inconsistent-return-statements + self, share_permission: Union[_models.SharePermission, IO[bytes]], timeout: Optional[int] = None, **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Create a permission (a security descriptor). + + :param share_permission: A permission (a security descriptor) at the share level. Is either a + SharePermission type or a IO[bytes] type. Required. + :type share_permission: ~azure.storage.fileshare.models.SharePermission or IO[bytes] + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["filepermission"] = kwargs.pop("comp", _params.pop("comp", "filepermission")) + content_type: Optional[str] = kwargs.pop("content_type", _headers.pop("Content-Type", None)) + cls: ClsType[None] = kwargs.pop("cls", None) + + content_type = content_type or "application/json" + _json = None + _content = None + if isinstance(share_permission, (IOBase, bytes)): + _content = share_permission + else: + _json = self._serialize.body(share_permission, "SharePermission") + + _request = build_create_permission_request( + url=self._config.url, + timeout=timeout, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + content_type=content_type, + version=self._config.version, + json=_json, + content=_content, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-file-permission-key"] = self._deserialize( + "str", response.headers.get("x-ms-file-permission-key") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def get_permission( + self, + file_permission_key: str, + file_permission_format: Optional[Union[str, _models.FilePermissionFormat]] = None, + timeout: Optional[int] = None, + **kwargs: Any + ) -> _models.SharePermission: + # pylint: disable=line-too-long + """Returns the permission (security descriptor) for a given key. + + :param file_permission_key: Key of the permission to be set for the directory/file. Required. + :type file_permission_key: str + :param file_permission_format: Optional. Available for version 2023-06-01 and later. Specifies + the format in which the permission is returned. Acceptable values are SDDL or binary. If + x-ms-file-permission-format is unspecified or explicitly set to SDDL, the permission is + returned in SDDL format. If x-ms-file-permission-format is explicitly set to binary, the + permission is returned as a base64 string representing the binary encoding of the permission. + Known values are: "Sddl" and "Binary". Default value is None. + :type file_permission_format: str or ~azure.storage.fileshare.models.FilePermissionFormat + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :return: SharePermission or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.SharePermission + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["filepermission"] = kwargs.pop("comp", _params.pop("comp", "filepermission")) + cls: ClsType[_models.SharePermission] = kwargs.pop("cls", None) + + _request = build_get_permission_request( + url=self._config.url, + file_permission_key=file_permission_key, + file_permission_format=file_permission_format, + timeout=timeout, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("SharePermission", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def set_properties( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + quota: Optional[int] = None, + access_tier: Optional[Union[str, _models.ShareAccessTier]] = None, + root_squash: Optional[Union[str, _models.ShareRootSquash]] = None, + enable_snapshot_virtual_directory_access: Optional[bool] = None, + paid_bursting_enabled: Optional[bool] = None, + paid_bursting_max_bandwidth_mibps: Optional[int] = None, + paid_bursting_max_iops: Optional[int] = None, + share_provisioned_iops: Optional[int] = None, + share_provisioned_bandwidth_mibps: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Sets properties for the specified share. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param quota: Specifies the maximum size of the share, in gigabytes. Default value is None. + :type quota: int + :param access_tier: Specifies the access tier of the share. Known values are: + "TransactionOptimized", "Hot", "Cool", and "Premium". Default value is None. + :type access_tier: str or ~azure.storage.fileshare.models.ShareAccessTier + :param root_squash: Root squash to set on the share. Only valid for NFS shares. Known values + are: "NoRootSquash", "RootSquash", and "AllSquash". Default value is None. + :type root_squash: str or ~azure.storage.fileshare.models.ShareRootSquash + :param enable_snapshot_virtual_directory_access: Default value is None. + :type enable_snapshot_virtual_directory_access: bool + :param paid_bursting_enabled: Optional. Boolean. Default if not specified is false. This + property enables paid bursting. Default value is None. + :type paid_bursting_enabled: bool + :param paid_bursting_max_bandwidth_mibps: Optional. Integer. Default if not specified is the + maximum throughput the file share can support. Current maximum for a file share is 10,340 + MiB/sec. Default value is None. + :type paid_bursting_max_bandwidth_mibps: int + :param paid_bursting_max_iops: Optional. Integer. Default if not specified is the maximum IOPS + the file share can support. Current maximum for a file share is 102,400 IOPS. Default value is + None. + :type paid_bursting_max_iops: int + :param share_provisioned_iops: Optional. Supported in version 2025-01-05 and later. Only + allowed for provisioned v2 file shares. Specifies the provisioned number of input/output + operations per second (IOPS) of the share. If this is not specified, the provisioned IOPS is + set to value calculated based on recommendation formula. Default value is None. + :type share_provisioned_iops: int + :param share_provisioned_bandwidth_mibps: Optional. Supported in version 2025-01-05 and later. + Only allowed for provisioned v2 file shares. Specifies the provisioned bandwidth of the share, + in mebibytes per second (MiBps). If this is not specified, the provisioned bandwidth is set to + value calculated based on recommendation formula. Default value is None. + :type share_provisioned_bandwidth_mibps: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["properties"] = kwargs.pop("comp", _params.pop("comp", "properties")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_set_properties_request( + url=self._config.url, + timeout=timeout, + quota=quota, + access_tier=access_tier, + lease_id=_lease_id, + root_squash=root_squash, + enable_snapshot_virtual_directory_access=enable_snapshot_virtual_directory_access, + paid_bursting_enabled=paid_bursting_enabled, + paid_bursting_max_bandwidth_mibps=paid_bursting_max_bandwidth_mibps, + paid_bursting_max_iops=paid_bursting_max_iops, + share_provisioned_iops=share_provisioned_iops, + share_provisioned_bandwidth_mibps=share_provisioned_bandwidth_mibps, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-share-quota"] = self._deserialize("int", response.headers.get("x-ms-share-quota")) + response_headers["x-ms-share-provisioned-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-iops") + ) + response_headers["x-ms-share-provisioned-bandwidth-mibps"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-bandwidth-mibps") + ) + response_headers["x-ms-share-included-burst-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-included-burst-iops") + ) + response_headers["x-ms-share-max-burst-credits-for-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-max-burst-credits-for-iops") + ) + response_headers["x-ms-share-next-allowed-quota-downgrade-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-share-next-allowed-quota-downgrade-time") + ) + response_headers["x-ms-share-next-allowed-provisioned-iops-downgrade-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-share-next-allowed-provisioned-iops-downgrade-time") + ) + response_headers["x-ms-share-next-allowed-provisioned-bandwidth-downgrade-time"] = self._deserialize( + "rfc-1123", response.headers.get("x-ms-share-next-allowed-provisioned-bandwidth-downgrade-time") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def set_metadata( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + metadata: Optional[Dict[str, str]] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Sets one or more user-defined name-value pairs for the specified share. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param metadata: A name-value pair to associate with a file storage object. Default value is + None. + :type metadata: dict[str, str] + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["metadata"] = kwargs.pop("comp", _params.pop("comp", "metadata")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_set_metadata_request( + url=self._config.url, + timeout=timeout, + metadata=metadata, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def get_access_policy( + self, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> List[_models.SignedIdentifier]: + # pylint: disable=line-too-long + """Returns information about stored access policies specified on the share. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: list of SignedIdentifier or the result of cls(response) + :rtype: list[~azure.storage.fileshare.models.SignedIdentifier] + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["acl"] = kwargs.pop("comp", _params.pop("comp", "acl")) + cls: ClsType[List[_models.SignedIdentifier]] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_get_access_policy_request( + url=self._config.url, + timeout=timeout, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("[SignedIdentifier]", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def set_access_policy( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + share_acl: Optional[List[_models.SignedIdentifier]] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Sets a stored access policy for use with shared access signatures. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :param share_acl: The ACL for the share. Default value is None. + :type share_acl: list[~azure.storage.fileshare.models.SignedIdentifier] + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = case_insensitive_dict(kwargs.pop("headers", {}) or {}) + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["acl"] = kwargs.pop("comp", _params.pop("comp", "acl")) + content_type: str = kwargs.pop("content_type", _headers.pop("Content-Type", "application/xml")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + serialization_ctxt = {"xml": {"name": "SignedIdentifiers", "wrapped": True}} + if share_acl is not None: + _content = self._serialize.body( + share_acl, "[SignedIdentifier]", is_xml=True, serialization_ctxt=serialization_ctxt + ) + else: + _content = None + + _request = build_set_access_policy_request( + url=self._config.url, + timeout=timeout, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + content_type=content_type, + version=self._config.version, + content=_content, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore + + @distributed_trace + def get_statistics( + self, + timeout: Optional[int] = None, + lease_access_conditions: Optional[_models.LeaseAccessConditions] = None, + **kwargs: Any + ) -> _models.ShareStats: + # pylint: disable=line-too-long + """Retrieves statistics related to the share. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param lease_access_conditions: Parameter group. Default value is None. + :type lease_access_conditions: ~azure.storage.fileshare.models.LeaseAccessConditions + :return: ShareStats or the result of cls(response) + :rtype: ~azure.storage.fileshare.models.ShareStats + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["stats"] = kwargs.pop("comp", _params.pop("comp", "stats")) + cls: ClsType[_models.ShareStats] = kwargs.pop("cls", None) + + _lease_id = None + if lease_access_conditions is not None: + _lease_id = lease_access_conditions.lease_id + + _request = build_get_statistics_request( + url=self._config.url, + timeout=timeout, + lease_id=_lease_id, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [200]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + + deserialized = self._deserialize("ShareStats", pipeline_response.http_response) + + if cls: + return cls(pipeline_response, deserialized, response_headers) # type: ignore + + return deserialized # type: ignore + + @distributed_trace + def restore( # pylint: disable=inconsistent-return-statements + self, + timeout: Optional[int] = None, + request_id_parameter: Optional[str] = None, + deleted_share_name: Optional[str] = None, + deleted_share_version: Optional[str] = None, + **kwargs: Any + ) -> None: + # pylint: disable=line-too-long + """Restores a previously deleted Share. + + :param timeout: The timeout parameter is expressed in seconds. For more information, see + :code:`<a + href="https://docs.microsoft.com/en-us/rest/api/storageservices/Setting-Timeouts-for-File-Service-Operations?redirectedfrom=MSDN">Setting + Timeouts for File Service Operations.</a>`. Default value is None. + :type timeout: int + :param request_id_parameter: Provides a client-generated, opaque value with a 1 KB character + limit that is recorded in the analytics logs when storage analytics logging is enabled. Default + value is None. + :type request_id_parameter: str + :param deleted_share_name: Specifies the name of the previously-deleted share. Default value is + None. + :type deleted_share_name: str + :param deleted_share_version: Specifies the version of the previously-deleted share. Default + value is None. + :type deleted_share_version: str + :return: None or the result of cls(response) + :rtype: None + :raises ~azure.core.exceptions.HttpResponseError: + """ + error_map: MutableMapping = { + 401: ClientAuthenticationError, + 404: ResourceNotFoundError, + 409: ResourceExistsError, + 304: ResourceNotModifiedError, + } + error_map.update(kwargs.pop("error_map", {}) or {}) + + _headers = kwargs.pop("headers", {}) or {} + _params = case_insensitive_dict(kwargs.pop("params", {}) or {}) + + restype: Literal["share"] = kwargs.pop("restype", _params.pop("restype", "share")) + comp: Literal["undelete"] = kwargs.pop("comp", _params.pop("comp", "undelete")) + cls: ClsType[None] = kwargs.pop("cls", None) + + _request = build_restore_request( + url=self._config.url, + timeout=timeout, + request_id_parameter=request_id_parameter, + deleted_share_name=deleted_share_name, + deleted_share_version=deleted_share_version, + file_request_intent=self._config.file_request_intent, + restype=restype, + comp=comp, + version=self._config.version, + headers=_headers, + params=_params, + ) + _request.url = self._client.format_url(_request.url) + + _stream = False + pipeline_response: PipelineResponse = self._client._pipeline.run( # pylint: disable=protected-access + _request, stream=_stream, **kwargs + ) + + response = pipeline_response.http_response + + if response.status_code not in [201]: + map_error(status_code=response.status_code, response=response, error_map=error_map) + error = self._deserialize.failsafe_deserialize(_models.StorageError, pipeline_response) + raise HttpResponseError(response=response, model=error) + + response_headers = {} + response_headers["ETag"] = self._deserialize("str", response.headers.get("ETag")) + response_headers["Last-Modified"] = self._deserialize("rfc-1123", response.headers.get("Last-Modified")) + response_headers["x-ms-request-id"] = self._deserialize("str", response.headers.get("x-ms-request-id")) + response_headers["x-ms-client-request-id"] = self._deserialize( + "str", response.headers.get("x-ms-client-request-id") + ) + response_headers["x-ms-version"] = self._deserialize("str", response.headers.get("x-ms-version")) + response_headers["Date"] = self._deserialize("rfc-1123", response.headers.get("Date")) + response_headers["x-ms-share-quota"] = self._deserialize("int", response.headers.get("x-ms-share-quota")) + response_headers["x-ms-share-provisioned-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-iops") + ) + response_headers["x-ms-share-provisioned-bandwidth-mibps"] = self._deserialize( + "int", response.headers.get("x-ms-share-provisioned-bandwidth-mibps") + ) + response_headers["x-ms-share-included-burst-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-included-burst-iops") + ) + response_headers["x-ms-share-max-burst-credits-for-iops"] = self._deserialize( + "int", response.headers.get("x-ms-share-max-burst-credits-for-iops") + ) + + if cls: + return cls(pipeline_response, None, response_headers) # type: ignore diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/py.typed b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/py.typed new file mode 100644 index 00000000..e5aff4f8 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_generated/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561.
\ No newline at end of file diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_lease.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_lease.py new file mode 100644 index 00000000..aa65f693 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_lease.py @@ -0,0 +1,251 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=docstring-keyword-should-match-keyword-only + +import uuid + +from typing import Union, Optional, Any, TYPE_CHECKING + +from azure.core.tracing.decorator import distributed_trace +from azure.core.exceptions import HttpResponseError + +from ._shared.response_handlers import return_response_headers, process_storage_error +from ._generated.operations import FileOperations, ShareOperations + +if TYPE_CHECKING: + from datetime import datetime + from azure.storage.fileshare import ShareClient, ShareFileClient + + +class ShareLeaseClient(object): # pylint: disable=client-accepts-api-version-keyword + """Creates a new ShareLeaseClient. + + This client provides lease operations on a ShareClient or ShareFileClient. + + :param client: + The client of the file or share to lease. + :type client: ~azure.storage.fileshare.ShareFileClient or + ~azure.storage.fileshare.ShareClient + :param str lease_id: + A string representing the lease ID of an existing lease. This value does not + need to be specified in order to acquire a new lease, or break one. + """ + + id: str + """The ID of the lease currently being maintained. This will be `None` if no + lease has yet been acquired.""" + etag: Optional[str] + """The ETag of the lease currently being maintained. This will be `None` if no + lease has yet been acquired or modified.""" + last_modified: Optional["datetime"] + """The last modified timestamp of the lease currently being maintained. + This will be `None` if no lease has yet been acquired or modified.""" + + def __init__( # pylint: disable=missing-client-constructor-parameter-credential, missing-client-constructor-parameter-kwargs + self, client: Union["ShareFileClient", "ShareClient"], + lease_id: Optional[str] = None + ) -> None: + self.id = lease_id or str(uuid.uuid4()) + self.last_modified = None + self.etag = None + if hasattr(client, 'file_name'): + self._client = client._client.file # type: ignore + self._snapshot = None + elif hasattr(client, 'share_name'): + self._client = client._client.share + self._snapshot = client.snapshot + else: + raise TypeError("Lease must use ShareFileClient or ShareClient.") + + def __enter__(self): + return self + + def __exit__(self, *args: Any): + self.release() + + @distributed_trace + def acquire(self, **kwargs: Any) -> None: + """Requests a new lease. This operation establishes and manages a lock on a + file or share for write and delete operations. If the file or share does not have an active lease, + the File or Share service creates a lease on the file or share. If the file has an active lease, + you can only request a new lease using the active lease ID. + + + If the file or share does not have an active lease, the File or Share service creates a + lease on the file and returns a new lease ID. + + :keyword int lease_duration: + Specifies the duration of the lease, in seconds, or negative one + (-1) for a lease that never expires. File leases never expire. A non-infinite share lease can be + between 15 and 60 seconds. A share lease duration cannot be changed + using renew or change. Default is -1 (infinite share lease). + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + """ + try: + lease_duration = kwargs.pop('lease_duration', -1) + if self._snapshot: + kwargs['sharesnapshot'] = self._snapshot + response = self._client.acquire_lease( + timeout=kwargs.pop('timeout', None), + duration=lease_duration, + proposed_lease_id=self.id, + cls=return_response_headers, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + self.id = response.get('lease_id') + self.last_modified = response.get('last_modified') + self.etag = response.get('etag') + + @distributed_trace + def renew(self, **kwargs: Any) -> None: + """Renews the share lease. + + The share lease can be renewed if the lease ID specified in the + lease client matches that associated with the share. Note that + the lease may be renewed even if it has expired as long as the share + has not been leased again since the expiration of that lease. When you + renew a lease, the lease duration clock resets. + + .. versionadded:: 12.6.0 + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :return: None + """ + if isinstance(self._client, FileOperations): + raise TypeError("Lease renewal operations are only valid for ShareClient.") + try: + response = self._client.renew_lease( + lease_id=self.id, + timeout=kwargs.pop('timeout', None), + sharesnapshot=self._snapshot, + cls=return_response_headers, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + self.etag = response.get('etag') + self.id = response.get('lease_id') + self.last_modified = response.get('last_modified') + + @distributed_trace + def release(self, **kwargs: Any) -> None: + """Releases the lease. The lease may be released if the lease ID specified on the request matches + that associated with the share or file. Releasing the lease allows another client to immediately acquire + the lease for the share or file as soon as the release is complete. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :return: None + """ + try: + if self._snapshot: + kwargs['sharesnapshot'] = self._snapshot + response = self._client.release_lease( + lease_id=self.id, + timeout=kwargs.pop('timeout', None), + cls=return_response_headers, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + self.etag = response.get('etag') + self.id = response.get('lease_id') + self.last_modified = response.get('last_modified') + + @distributed_trace + def change(self, proposed_lease_id: str, **kwargs: Any) -> None: + """ Changes the lease ID of an active lease. A change must include the current lease ID in x-ms-lease-id and + a new lease ID in x-ms-proposed-lease-id. + + :param str proposed_lease_id: + Proposed lease ID, in a GUID string format. The File or Share service will raise an error + (Invalid request) if the proposed lease ID is not in the correct format. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :return: None + """ + try: + if self._snapshot: + kwargs['sharesnapshot'] = self._snapshot + response = self._client.change_lease( + lease_id=self.id, + proposed_lease_id=proposed_lease_id, + timeout=kwargs.pop('timeout', None), + cls=return_response_headers, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + self.etag = response.get('etag') + self.id = response.get('lease_id') + self.last_modified = response.get('last_modified') + + @distributed_trace + def break_lease(self, **kwargs: Any) -> int: + """Force breaks the lease if the file or share has an active lease. Any authorized request can break the lease; + the request is not required to specify a matching lease ID. An infinite lease breaks immediately. + + Once a lease is broken, it cannot be changed. Any authorized request can break the lease; + the request is not required to specify a matching lease ID. + When a lease is successfully broken, the response indicates the interval + in seconds until a new lease can be acquired. + + :keyword int lease_break_period: + This is the proposed duration of seconds that the share lease + should continue before it is broken, between 0 and 60 seconds. This + break period is only used if it is shorter than the time remaining + on the share lease. If longer, the time remaining on the share lease is used. + A new share lease will not be available before the break period has + expired, but the share lease may be held for longer than the break + period. If this header does not appear with a break + operation, a fixed-duration share lease breaks after the remaining share lease + period elapses, and an infinite share lease breaks immediately. + + .. versionadded:: 12.6.0 + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :return: Approximate time remaining in the lease period, in seconds. + :rtype: int + """ + try: + lease_break_period = kwargs.pop('lease_break_period', None) + if self._snapshot: + kwargs['sharesnapshot'] = self._snapshot + if isinstance(self._client, ShareOperations): + kwargs['break_period'] = lease_break_period + if isinstance(self._client, FileOperations) and lease_break_period: + raise TypeError("Setting a lease break period is only applicable to Share leases.") + + response = self._client.break_lease( + timeout=kwargs.pop('timeout', None), + cls=return_response_headers, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + return response.get('lease_time') # type: ignore diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_models.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_models.py new file mode 100644 index 00000000..ec95b64c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_models.py @@ -0,0 +1,1294 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=too-few-public-methods, too-many-instance-attributes, super-init-not-called, too-many-lines + +from enum import Enum +from typing import ( + Any, Callable, Dict, List, Literal, Optional, Union, + TYPE_CHECKING +) +from urllib.parse import unquote +from typing_extensions import Self + +from azure.core import CaseInsensitiveEnumMeta +from azure.core.exceptions import HttpResponseError +from azure.core.paging import PageIterator + +from ._generated.models import AccessPolicy as GenAccessPolicy +from ._generated.models import CorsRule as GeneratedCorsRule +from ._generated.models import DirectoryItem +from ._generated.models import Metrics as GeneratedMetrics +from ._generated.models import RetentionPolicy as GeneratedRetentionPolicy +from ._generated.models import ShareProtocolSettings as GeneratedShareProtocolSettings +from ._generated.models import ShareSmbSettings as GeneratedShareSmbSettings +from ._generated.models import SmbMultichannel as GeneratedSmbMultichannel +from ._generated.models import StorageServiceProperties as GeneratedStorageServiceProperties +from ._parser import _parse_datetime_from_str +from ._shared.models import DictMixin, get_enum_value +from ._shared.response_handlers import process_storage_error, return_context_and_deserialized + +if TYPE_CHECKING: + from datetime import datetime + from ._generated.models import ShareRootSquash + + +def _wrap_item(item): + if isinstance(item, DirectoryItem): + return {'name': item.name, 'is_directory': True} + return {'name': item.name, 'size': item.properties.content_length, 'is_directory': False} + + +class RetentionPolicy(GeneratedRetentionPolicy): + """The retention policy which determines how long the associated data should + persist. + + All required parameters must be populated in order to send to Azure. + + :param bool enabled: + Indicates whether a retention policy is enabled for the storage service. + :param Optional[int] days: + Indicates the number of days that metrics or logging or soft-deleted data should be retained. + All data older than this value will be deleted. + """ + + enabled: bool = False + """Indicates whether a retention policy is enabled for the storage service.""" + days: Optional[int] = None + """Indicates the number of days that metrics or logging or soft-deleted data should be retained. + All data older than this value will be deleted.""" + + def __init__(self, enabled: bool = False, days: Optional[int] = None) -> None: + self.enabled = enabled + self.days = days + if self.enabled and (self.days is None): + raise ValueError("If policy is enabled, 'days' must be specified.") + + @classmethod + def _from_generated(cls, generated): + if not generated: + return cls() + return cls( + enabled=generated.enabled, + days=generated.days, + ) + + +class Metrics(GeneratedMetrics): + """A summary of request statistics grouped by API in hour or minute aggregates + for files. + + All required parameters must be populated in order to send to Azure. + + :keyword str version: + The version of Storage Analytics to configure. The default value is 1.0. + :keyword bool enabled: + Indicates whether metrics are enabled for the File service. + :keyword bool include_apis: + Indicates whether metrics should generate summary statistics for called API operations. + :keyword ~azure.storage.fileshare.RetentionPolicy retention_policy: + Determines how long the associated data should persist. + """ + + version: str = '1.0' + """The version of Storage Analytics to configure.""" + enabled: bool = False + """Indicates whether metrics are enabled for the File service.""" + include_apis: bool + """Indicates whether metrics should generate summary statistics for called API operations.""" + retention_policy: RetentionPolicy = RetentionPolicy() + """Determines how long the associated data should persist.""" + + def __init__(self, **kwargs: Any) -> None: + self.version = kwargs.get('version', '1.0') + self.enabled = kwargs.get('enabled', False) + self.include_apis = kwargs.get('include_apis') # type: ignore [assignment] + self.retention_policy = kwargs.get('retention_policy') or RetentionPolicy() + + @classmethod + def _from_generated(cls, generated): + if not generated: + return cls() + return cls( + version=generated.version, + enabled=generated.enabled, + include_apis=generated.include_apis, + retention_policy=RetentionPolicy._from_generated(generated.retention_policy) # pylint: disable=protected-access + ) + + +class CorsRule(GeneratedCorsRule): + """CORS is an HTTP feature that enables a web application running under one + domain to access resources in another domain. Web browsers implement a + security restriction known as same-origin policy that prevents a web page + from calling APIs in a different domain; CORS provides a secure way to + allow one domain (the origin domain) to call APIs in another domain. + + All required parameters must be populated in order to send to Azure. + + :param List[str] allowed_origins: + A list of origin domains that will be allowed via CORS, or "*" to allow + all domains. The list of must contain at least one entry. Limited to 64 + origin domains. Each allowed origin can have up to 256 characters. + :param List[str] allowed_methods: + A list of HTTP methods that are allowed to be executed by the origin. + The list of must contain at least one entry. For Azure Storage, + permitted methods are DELETE, GET, HEAD, MERGE, POST, OPTIONS or PUT. + :keyword List[str] allowed_headers: + Defaults to an empty list. A list of headers allowed to be part of + the cross-origin request. Limited to 64 defined headers and 2 prefixed + headers. Each header can be up to 256 characters. + :keyword List[str] exposed_headers: + Defaults to an empty list. A list of response headers to expose to CORS + clients. Limited to 64 defined headers and two prefixed headers. Each + header can be up to 256 characters. + :keyword int max_age_in_seconds: + The number of seconds that the client/browser should cache a + preflight response. + """ + + allowed_origins: str + """The comma-delimited string representation of the list of origin domains + that will be allowed via CORS, or "*" to allow all domains.""" + allowed_methods: str + """The comma-delimited string representation of the list of HTTP methods + that are allowed to be executed by the origin.""" + allowed_headers: str + """The comma-delimited string representation of the list of headers + allowed to be a part of the cross-origin request.""" + exposed_headers: str + """The comma-delimited string representation of the list of response + headers to expose to CORS clients.""" + max_age_in_seconds: int + """The number of seconds that the client/browser should cache a pre-flight response.""" + + def __init__(self, allowed_origins: List[str], allowed_methods: List[str], **kwargs: Any) -> None: + self.allowed_origins = ','.join(allowed_origins) + self.allowed_methods = ','.join(allowed_methods) + self.allowed_headers = ','.join(kwargs.get('allowed_headers', [])) + self.exposed_headers = ','.join(kwargs.get('exposed_headers', [])) + self.max_age_in_seconds = kwargs.get('max_age_in_seconds', 0) + + @staticmethod + def _to_generated(rules: Optional[List["CorsRule"]]) -> Optional[List[GeneratedCorsRule]]: + if rules is None: + return rules + + generated_cors_list = [] + for cors_rule in rules: + generated_cors = GeneratedCorsRule( + allowed_origins=cors_rule.allowed_origins, + allowed_methods=cors_rule.allowed_methods, + allowed_headers=cors_rule.allowed_headers, + exposed_headers=cors_rule.exposed_headers, + max_age_in_seconds=cors_rule.max_age_in_seconds, + ) + generated_cors_list.append(generated_cors) + + return generated_cors_list + + @classmethod + def _from_generated(cls, generated): + return cls( + [generated.allowed_origins], + [generated.allowed_methods], + allowed_headers=[generated.allowed_headers], + exposed_headers=[generated.exposed_headers], + max_age_in_seconds=generated.max_age_in_seconds, + ) + + +class SmbMultichannel(GeneratedSmbMultichannel): + """Settings for Multichannel. + + :keyword bool enabled: If SMB Multichannel is enabled. + """ + + enabled: Optional[bool] + """If SMB Multichannel is enabled.""" + + def __init__(self, **kwargs: Any) -> None: + self.enabled = kwargs.get('enabled') + if self.enabled is None: + raise ValueError("The value 'enabled' must be specified.") + + +class ShareSmbSettings(GeneratedShareSmbSettings): + """Settings for the SMB protocol. + + :keyword SmbMultichannel multichannel: Sets the multichannel settings. + """ + + multichannel: SmbMultichannel + """Sets the multichannel settings.""" + + def __init__(self, **kwargs: Any) -> None: + self.multichannel = kwargs.get('multichannel') # type: ignore [assignment] + if self.multichannel is None: + raise ValueError("The value 'multichannel' must be specified.") + + +class ShareProtocolSettings(GeneratedShareProtocolSettings): + """Protocol Settings class used by the set and get service properties methods in the share service. + + Contains protocol properties of the share service such as the SMB setting of the share service. + + :keyword ShareSmbSettings smb: Sets SMB settings. + """ + + smb: ShareSmbSettings + """Sets the SMB settings.""" + + def __init__(self, **kwargs: Any) -> None: + self.smb = kwargs.get('smb') # type: ignore [assignment] + if self.smb is None: + raise ValueError("The value 'smb' must be specified.") + + @classmethod + def _from_generated(cls, generated): + return cls( + smb=generated.smb) + + +class ShareSasPermissions(object): + """ShareSasPermissions class to be used to be used with + generating shared access signature and access policy operations. + + :param bool read: + Read the content, properties or metadata of any file in the share. Use any + file in the share as the source of a copy operation. + :param bool write: + For any file in the share, create or write content, properties or metadata. + Resize the file. Use the file as the destination of a copy operation within + the same account. + Note: You cannot grant permissions to read or write share properties or + metadata with a service SAS. Use an account SAS instead. + :param bool delete: + Delete any file in the share. + Note: You cannot grant permissions to delete a share with a service SAS. Use + an account SAS instead. + :param bool list: + List files and directories in the share. + :param bool create: + Create a new file in the share, or copy a file to a new file in the share. + """ + + read: bool = False + """The read permission for share SAS.""" + write: bool = False + """The write permission for share SAS.""" + delete: bool = False + """The delete permission for share SAS.""" + list: bool = False + """The list permission for share SAS.""" + create: bool = False + """The create permission for share SAS.""" + + def __init__( + self, read: bool = False, + write: bool = False, + delete: bool = False, + list: bool = False, + create: bool = False + ) -> None: + self.read = read + self.create = create + self.write = write + self.delete = delete + self.list = list + self._str = (('r' if self.read else '') + + ('c' if self.create else '') + + ('w' if self.write else '') + + ('d' if self.delete else '') + + ('l' if self.list else '')) + + def __str__(self) -> str: + return self._str + + @classmethod + def from_string(cls, permission: str) -> Self: + """Create a ShareSasPermissions from a string. + + To specify read, create, write, delete, or list permissions you need only to + include the first letter of the word in the string. E.g. For read and + write permissions, you would provide a string "rw". + + :param str permission: The string which dictates the read, create, write, + delete, or list permissions + :return: A ShareSasPermissions object + :rtype: ~azure.storage.fileshare.ShareSasPermissions + """ + p_read = 'r' in permission + p_create = 'c' in permission + p_write = 'w' in permission + p_delete = 'd' in permission + p_list = 'l' in permission + + parsed = cls(p_read, p_write, p_delete, p_list, p_create) + + return parsed + + +class AccessPolicy(GenAccessPolicy): + """Access Policy class used by the set and get acl methods in each service. + + A stored access policy can specify the start time, expiry time, and + permissions for the Shared Access Signatures with which it's associated. + Depending on how you want to control access to your resource, you can + specify all of these parameters within the stored access policy, and omit + them from the URL for the Shared Access Signature. Doing so permits you to + modify the associated signature's behavior at any time, as well as to revoke + it. Or you can specify one or more of the access policy parameters within + the stored access policy, and the others on the URL. Finally, you can + specify all of the parameters on the URL. In this case, you can use the + stored access policy to revoke the signature, but not to modify its behavior. + + Together the Shared Access Signature and the stored access policy must + include all fields required to authenticate the signature. If any required + fields are missing, the request will fail. Likewise, if a field is specified + both in the Shared Access Signature URL and in the stored access policy, the + request will fail with status code 400 (Bad Request). + + :param permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has been + specified in an associated stored access policy. + :type permission: str or ~azure.storage.fileshare.FileSasPermissions or + ~azure.storage.fileshare.ShareSasPermissions + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: ~datetime.datetime or str + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. The provided datetime will always + be interpreted as UTC. + :type start: ~datetime.datetime or str + """ + + permission: Optional[Union[ShareSasPermissions, str]] # type: ignore [assignment] + """The permissions associated with the shared access signature. The user is restricted to + operations allowed by the permissions.""" + expiry: Optional[Union["datetime", str]] # type: ignore [assignment] + """The time at which the shared access signature becomes invalid.""" + start: Optional[Union["datetime", str]] # type: ignore [assignment] + """The time at which the shared access signature becomes valid.""" + + def __init__( + self, permission: Optional[Union[ShareSasPermissions, str]] = None, + expiry: Optional[Union["datetime", str]] = None, + start: Optional[Union["datetime", str]] = None + ) -> None: + self.start = start + self.expiry = expiry + self.permission = permission + + +class LeaseProperties(DictMixin): + """File or Share Lease Properties.""" + + status: str + """The lease status of the file or share. Possible values: locked|unlocked""" + state: str + """Lease state of the file or share. Possible values: available|leased|expired|breaking|broken""" + duration: Optional[str] + """When a file or share is leased, specifies whether the lease is of infinite or fixed duration.""" + + def __init__(self, **kwargs: Any) -> None: + self.status = get_enum_value(kwargs.get('x-ms-lease-status')) + self.state = get_enum_value(kwargs.get('x-ms-lease-state')) + self.duration = get_enum_value(kwargs.get('x-ms-lease-duration')) + + @classmethod + def _from_generated(cls, generated): + lease = cls() + lease.status = get_enum_value(generated.properties.lease_status) + lease.state = get_enum_value(generated.properties.lease_state) + lease.duration = get_enum_value(generated.properties.lease_duration) + return lease + + +class ContentSettings(DictMixin): + """Used to store the content settings of a file. + + :param Optional[str] content_type: + The content type specified for the file. If no content type was + specified, the default content type is application/octet-stream. + :param Optional[str] content_encoding: + If the content_encoding has previously been set + for the file, that value is stored. + :param Optional[str] content_language: + If the content_language has previously been set + for the file, that value is stored. + :param Optional[str] content_disposition: + content_disposition conveys additional information about how to + process the response payload, and also can be used to attach + additional metadata. If content_disposition has previously been set + for the file, that value is stored. + :param Optional[str] cache_control: + If the cache_control has previously been set for + the file, that value is stored. + :param Optional[bytearray] content_md5: + If the content_md5 has been set for the file, this response + header is stored so that the client can check for message content + integrity. + """ + + content_type: Optional[str] = None + """The content type specified for the file.""" + content_encoding: Optional[str] = None + """The content encoding specified for the file.""" + content_language: Optional[str] = None + """The content language specified for the file.""" + content_disposition: Optional[str] = None + """The content disposition specified for the file.""" + cache_control: Optional[str] = None + """The cache control specified for the file.""" + content_md5: Optional[bytearray] = None + """The content md5 specified for the file.""" + + def __init__( + self, content_type: Optional[str] = None, + content_encoding: Optional[str] = None, + content_language: Optional[str] = None, + content_disposition: Optional[str] = None, + cache_control: Optional[str] = None, + content_md5: Optional[bytearray] = None, + **kwargs: Any + ) -> None: + self.content_type = content_type or kwargs.get('Content-Type') + self.content_encoding = content_encoding or kwargs.get('Content-Encoding') + self.content_language = content_language or kwargs.get('Content-Language') + self.content_md5 = content_md5 or kwargs.get('Content-MD5') + self.content_disposition = content_disposition or kwargs.get('Content-Disposition') + self.cache_control = cache_control or kwargs.get('Cache-Control') + + @classmethod + def _from_generated(cls, generated): + settings = cls() + settings.content_type = generated.properties.content_type or None + settings.content_encoding = generated.properties.content_encoding or None + settings.content_language = generated.properties.content_language or None + settings.content_md5 = generated.properties.content_md5 or None + settings.content_disposition = generated.properties.content_disposition or None + settings.cache_control = generated.properties.cache_control or None + return settings + + +class ShareProperties(DictMixin): + """Share's properties class.""" + + name: str + """The name of the share.""" + last_modified: "datetime" + """A datetime object representing the last time the share was modified.""" + etag: str + """The ETag contains a value that you can use to perform operations conditionally.""" + quota: int + """The allocated quota.""" + access_tier: str + """The share's access tier.'""" + next_allowed_quota_downgrade_time: Optional[str] = None + """The share's next allowed quota downgrade time.""" + metadata: Dict[str, str] + """Name-value pairs associate with the share as metadata.""" + snapshot: Optional[str] = None + """Snapshot of the share.""" + deleted: Optional[bool] = None + """Whether this share was deleted. + This is a service returned value, and the value will be set when list shared including deleted ones.""" + deleted_time: Optional["datetime"] = None + """A datetime object representing the time at which the share was deleted. + This is a service returned value, and the value will be set when list shared including deleted ones.""" + version: Optional[str] = None + """To indicate the version of deleted share. + This is a service returned value, and the value will be set when list shared including deleted ones.""" + remaining_retention_days: Optional[int] = None + """The number of days that the share will be retained before being permanently deleted by the service. + This is a service returned value, and the value will be set when list shared including deleted ones.""" + provisioned_egress_mbps: Optional[int] = None + """Provisioned egress in megabits/second. Only applicable to premium file accounts.""" + provisioned_ingress_mbps: Optional[int] = None + """Provisioned ingress in megabits/second. Only applicable to premium file accounts.""" + provisioned_iops: Optional[int] = None + """Provisioned input/output operators per second (iops). Only applicable to premium file accounts.""" + provisioned_bandwidth: Optional[int] = None + """Provisioned bandwidth in megabits/second. Only applicable to premium file accounts.""" + lease: LeaseProperties + """Share lease properties.""" + protocols: Optional[List[str]] = None + """Indicates the protocols enabled on the share. The protocol can be either SMB or NFS.""" + root_squash: Optional[Union["ShareRootSquash", str]] = None + """Possible values include: 'NoRootSquash', 'RootSquash', 'AllSquash'.""" + enable_snapshot_virtual_directory_access: Optional[bool] = None + """Specifies whether the snapshot virtual directory should be accessible at the root of the share + mount point when NFS is enabled. if not specified, the default is True.""" + paid_bursting_enabled: Optional[int] = None + """This property enables paid bursting.""" + paid_bursting_bandwidth_mibps: Optional[int] = None + """The maximum throughput the file share can support in MiB/s.""" + paid_bursting_iops: Optional[int] = None + """The maximum IOPS the file share can support.""" + next_provisioned_iops_downgrade: Optional["datetime"] + """The share's next allowed provisioned throughput downgrade time.""" + next_provisioned_bandwidth_downgrade: Optional["datetime"] + """The share's next allowed provisioned bandwidth downgrade time.""" + + def __init__(self, **kwargs: Any) -> None: + self.name = None # type: ignore [assignment] + self.last_modified = kwargs.get('Last-Modified') # type: ignore [assignment] + self.etag = kwargs.get('ETag') # type: ignore [assignment] + self.quota = kwargs.get('x-ms-share-quota') # type: ignore [assignment] + self.access_tier = kwargs.get('x-ms-access-tier') # type: ignore [assignment] + self.next_allowed_quota_downgrade_time = kwargs.get('x-ms-share-next-allowed-quota-downgrade-time') + self.metadata = kwargs.get('metadata') # type: ignore [assignment] + self.snapshot = None + self.deleted = None + self.deleted_time = None + self.version = None + self.remaining_retention_days = None + self.provisioned_egress_mbps = kwargs.get('x-ms-share-provisioned-egress-mbps') + self.provisioned_ingress_mbps = kwargs.get('x-ms-share-provisioned-ingress-mbps') + self.provisioned_iops = kwargs.get('x-ms-share-provisioned-iops') + self.provisioned_bandwidth = kwargs.get('x-ms-share-provisioned-bandwidth-mibps') + self.lease = LeaseProperties(**kwargs) + self.protocols = [protocol.strip() for protocol in kwargs.get('x-ms-enabled-protocols', None).split(',')]\ + if kwargs.get('x-ms-enabled-protocols', None) else None + self.root_squash = kwargs.get('x-ms-root-squash', None) + self.enable_snapshot_virtual_directory_access = \ + kwargs.get('x-ms-enable-snapshot-virtual-directory-access') + self.paid_bursting_enabled = kwargs.get('x-ms-share-paid-bursting-enabled') + self.paid_bursting_bandwidth_mibps = kwargs.get('x-ms-share-paid-bursting-max-bandwidth-mibps') + self.paid_bursting_iops = kwargs.get('x-ms-share-paid-bursting-max-iops') + self.included_burst_iops = kwargs.get('x-ms-share-included-burst-iops') + self.max_burst_credits_for_iops = kwargs.get('x-ms-share-max-burst-credits-for-iops') + self.next_provisioned_iops_downgrade = ( # pylint: disable=name-too-long + kwargs.get('x-ms-share-next-allowed-provisioned-iops-downgrade-time')) + self.next_provisioned_bandwidth_downgrade = ( # pylint: disable=name-too-long + kwargs.get('x-ms-share-next-allowed-provisioned-bandwidth-downgrade-time')) + + @classmethod + def _from_generated(cls, generated): + props = cls() + props.name = generated.name + props.last_modified = generated.properties.last_modified + props.etag = generated.properties.etag + props.quota = generated.properties.quota + props.access_tier = generated.properties.access_tier + props.next_allowed_quota_downgrade_time = generated.properties.next_allowed_quota_downgrade_time + props.metadata = generated.metadata + props.snapshot = generated.snapshot + props.deleted = generated.deleted + props.deleted_time = generated.properties.deleted_time + props.version = generated.version + props.remaining_retention_days = generated.properties.remaining_retention_days + props.provisioned_egress_mbps = generated.properties.provisioned_egress_m_bps + props.provisioned_ingress_mbps = generated.properties.provisioned_ingress_m_bps + props.provisioned_iops = generated.properties.provisioned_iops + props.provisioned_bandwidth = generated.properties.provisioned_bandwidth_mi_bps + props.lease = LeaseProperties._from_generated(generated) # pylint: disable=protected-access + props.protocols = [protocol.strip() for protocol in generated.properties.enabled_protocols.split(',')]\ + if generated.properties.enabled_protocols else None + props.root_squash = generated.properties.root_squash + props.enable_snapshot_virtual_directory_access = generated.properties.enable_snapshot_virtual_directory_access + props.paid_bursting_enabled = generated.properties.paid_bursting_enabled + props.paid_bursting_bandwidth_mibps = generated.properties.paid_bursting_max_bandwidth_mibps + props.paid_bursting_iops = generated.properties.paid_bursting_max_iops + props.included_burst_iops = generated.properties.included_burst_iops + props.max_burst_credits_for_iops = generated.properties.max_burst_credits_for_iops + props.next_provisioned_iops_downgrade = ( # pylint: disable=name-too-long + generated.properties.next_allowed_provisioned_iops_downgrade_time) + props.next_provisioned_bandwidth_downgrade = ( # pylint: disable=name-too-long + generated.properties.next_allowed_provisioned_bandwidth_downgrade_time) + return props + + +class SharePropertiesPaged(PageIterator): + """An iterable of Share properties. + + :param Callable command: Function to retrieve the next page of items. + :param Optional[str] prefix: Filters the results to return only shares whose names + begin with the specified prefix. + :param Optional[int] results_per_page: The maximum number of share names to retrieve per call. + :param Optional[str] continuation_token: An opaque continuation token to retrieve the next page of results. + """ + + service_endpoint: Optional[str] = None + """The service URL.""" + prefix: Optional[str] = None + """A filename prefix being used to filter the list.""" + marker: Optional[str] = None + """The continuation token of the current page of results.""" + results_per_page: Optional[int] = None + """The maximum number of results to retrieve per API call.""" + location_mode: Optional[str] = None + """The location mode being used to list results. The available + options include "primary" and "secondary".""" + current_page: List[ShareProperties] + """The current page of listed results.""" + + def __init__( + self, command: Callable, + prefix: Optional[str] = None, + results_per_page: Optional[int] = None, + continuation_token: Optional[str] = None + ) -> None: + super(SharePropertiesPaged, self).__init__( + get_next=self._get_next_cb, + extract_data=self._extract_data_cb, + continuation_token=continuation_token or "" + ) + self._command = command + self.service_endpoint = None + self.prefix = prefix + self.marker = None + self.results_per_page = results_per_page + self.location_mode = None + self.current_page = [] + + def _get_next_cb(self, continuation_token): + try: + return self._command( + marker=continuation_token or None, + maxresults=self.results_per_page, + prefix=self.prefix, + cls=return_context_and_deserialized, + use_location=self.location_mode) + except HttpResponseError as error: + process_storage_error(error) + + def _extract_data_cb(self, get_next_return): + self.location_mode, self._response = get_next_return + self.service_endpoint = self._response.service_endpoint + self.prefix = self._response.prefix + self.marker = self._response.marker + self.results_per_page = self._response.max_results + self.current_page = [ShareProperties._from_generated(i) for i in self._response.share_items] # pylint: disable=protected-access + return self._response.next_marker or None, self.current_page + + +class Handle(DictMixin): + """A listed Azure Storage handle item. + + All required parameters must be populated in order to send to Azure. + + :keyword str client_name: Name of the client machine where the share is being mounted. + :keyword str handle_id: XSMB service handle ID. + :keyword str path: File or directory name including full path starting from share root. + :keyword str file_id: FileId uniquely identifies the file or directory. + :keyword str parent_id: ParentId uniquely identifies the parent directory of the object. + :keyword str session_id: SMB session ID in context of which the file handle was opened. + :keyword str client_ip: Client IP that opened the handle. + :keyword ~datetime.datetime open_time: Time when the session that previously opened + the handle has last been reconnected. (UTC) + :keyword Optional[~datetime.datetime] last_reconnect_time: Time handle was last connected to. (UTC) + :keyword access_rights: Access rights of the handle. + :paramtype access_rights: List[Literal['Read', 'Write', 'Delete']] + """ + + client_name: str + """Name of the client machine where the share is being mounted.""" + id: str + """XSMB service handle ID.""" + path: str + """File or directory name including full path starting from share root.""" + file_id: str + """FileId uniquely identifies the file or directory.""" + parent_id: str + """ParentId uniquely identifies the parent directory of the object.""" + session_id: str + """SMB session ID in context of which the file handle was opened.""" + client_ip: str + """Client IP that opened the handle.""" + open_time: "datetime" + """Time when the session that previously opened the handle was last been reconnected. (UTC)""" + last_reconnect_time: Optional["datetime"] + """Time handle that was last connected to. (UTC)""" + access_rights: List[Literal['Read', 'Write', 'Delete']] + """Access rights of the handle.""" + + def __init__(self, **kwargs: Any) -> None: + self.client_name = kwargs.get('client_name') # type: ignore [assignment] + self.id = kwargs.get('handle_id') # type: ignore [assignment] + self.path = kwargs.get('path') # type: ignore [assignment] + self.file_id = kwargs.get('file_id') # type: ignore [assignment] + self.parent_id = kwargs.get('parent_id') # type: ignore [assignment] + self.session_id = kwargs.get('session_id') # type: ignore [assignment] + self.client_ip = kwargs.get('client_ip') # type: ignore [assignment] + self.open_time = kwargs.get('open_time') # type: ignore [assignment] + self.last_reconnect_time = kwargs.get('last_reconnect_time') + self.access_rights = kwargs.get('access_right_list') # type: ignore [assignment] + + @classmethod + def _from_generated(cls, generated): + handle = cls() + handle.client_name = generated.client_name + handle.id = generated.handle_id + handle.path = unquote(generated.path.content) if generated.path.encoded else generated.path.content + handle.file_id = generated.file_id + handle.parent_id = generated.parent_id + handle.session_id = generated.session_id + handle.client_ip = generated.client_ip + handle.open_time = generated.open_time + handle.last_reconnect_time = generated.last_reconnect_time + handle.access_rights = generated.access_right_list + return handle + + +class HandlesPaged(PageIterator): + """An iterable of Handles. + + :param Callable command: Function to retrieve the next page of items. + :param Optional[int] results_per_page: The maximum number of share names to retrieve per call. + :param Optional[str] continuation_token: An opaque continuation token to retrieve the next page of results. + """ + + marker: Optional[str] = None + """The continuation token of the current page of results.""" + results_per_page: Optional[int] = None + """The maximum number of results retrieved per API call.""" + location_mode: Optional[str] = None + """The location mode being used to list results. + The available options include "primary" and "secondary".""" + current_page: List[Handle] + """The current page of listed results.""" + + def __init__( + self, command: Callable, + results_per_page: Optional[int] = None, + continuation_token: Optional[str] = None + ) -> None: + super(HandlesPaged, self).__init__( + get_next=self._get_next_cb, + extract_data=self._extract_data_cb, + continuation_token=continuation_token or "" + ) + self._command = command + self.marker = None + self.results_per_page = results_per_page + self.location_mode = None + self.current_page = [] + + def _get_next_cb(self, continuation_token): + try: + return self._command( + marker=continuation_token or None, + maxresults=self.results_per_page, + cls=return_context_and_deserialized, + use_location=self.location_mode) + except HttpResponseError as error: + process_storage_error(error) + + def _extract_data_cb(self, get_next_return): + self.location_mode, self._response = get_next_return + self.current_page = [Handle._from_generated(h) for h in self._response.handle_list] # pylint: disable=protected-access + return self._response.next_marker or None, self.current_page + + +class NTFSAttributes(object): + """Valid set of attributes to set for file or directory. + + To set attribute for directory, 'Directory' should always be enabled except setting 'None' for directory. + """ + + read_only: bool = False + """Enable/disable 'ReadOnly' attribute for DIRECTORY or FILE.""" + hidden: bool = False + """Enable/disable 'Hidden' attribute for DIRECTORY or FILE.""" + system: bool = False + """Enable/disable 'System' attribute for DIRECTORY or FILE.""" + none: bool = False + """Enable/disable 'None' attribute for DIRECTORY or FILE to clear all attributes of FILE/DIRECTORY.""" + directory: bool = False + """Enable/disable 'Directory' attribute for DIRECTORY.""" + archive: bool = False + """Enable/disable 'Archive' attribute for DIRECTORY.""" + temporary: bool = False + """Enable/disable 'Temporary' attribute for DIRECTORY.""" + offline: bool = False + """Enable/disable 'Offline' attribute for DIRECTORY.""" + not_content_indexed: bool = False + """Enable/disable 'NotContentIndexed' attribute for DIRECTORY.""" + no_scrub_data: bool = False + """Enable/disable 'NoScrubData' attribute for DIRECTORY.""" + + def __init__( + self, read_only: bool = False, + hidden: bool = False, + system: bool = False, + none: bool = False, + directory: bool = False, + archive: bool = False, + temporary: bool = False, + offline: bool = False, + not_content_indexed: bool = False, + no_scrub_data: bool = False + ) -> None: + self.read_only = read_only + self.hidden = hidden + self.system = system + self.none = none + self.directory = directory + self.archive = archive + self.temporary = temporary + self.offline = offline + self.not_content_indexed = not_content_indexed + self.no_scrub_data = no_scrub_data + self._str = (('ReadOnly|' if self.read_only else '') + + ('Hidden|' if self.hidden else '') + + ('System|' if self.system else '') + + ('None|' if self.none else '') + + ('Directory|' if self.directory else '') + + ('Archive|' if self.archive else '') + + ('Temporary|' if self.temporary else '') + + ('Offline|' if self.offline else '') + + ('NotContentIndexed|' if self.not_content_indexed else '') + + ('NoScrubData|' if self.no_scrub_data else '')) + + def __str__(self): + concatenated_params = self._str + return concatenated_params.strip('|') + + @classmethod + def from_string(cls, string: str) -> Self: + """Create a NTFSAttributes from a string. + + To specify permissions you can pass in a string with the + desired permissions, e.g. "ReadOnly|Hidden|System" + + :param str string: The string which dictates the permissions. + :return: A NTFSAttributes object + :rtype: ~azure.storage.fileshare.NTFSAttributes + """ + read_only = "ReadOnly" in string + hidden = "Hidden" in string + system = "System" in string + none = "None" in string + directory = "Directory" in string + archive = "Archive" in string + temporary = "Temporary" in string + offline = "Offline" in string + not_content_indexed = "NotContentIndexed" in string + no_scrub_data = "NoScrubData" in string + + parsed = cls(read_only, hidden, system, none, directory, archive, temporary, offline, not_content_indexed, + no_scrub_data) + parsed._str = string + return parsed + + +class DirectoryProperties(DictMixin): + """Directory's properties class.""" + + name: str + """The name of the directory.""" + last_modified: "datetime" + """A datetime object representing the last time the directory was modified.""" + etag: str + """The ETag contains a value that you can use to perform operations conditionally.""" + server_encrypted: bool + """Whether encryption is enabled.""" + metadata: Dict[str, str] + """Name_value pairs to associate with the directory as metadata.""" + change_time: Optional[Union[str, "datetime"]] = None + """Change time for the file.""" + creation_time: Optional[Union[str, "datetime"]] = None + """Creation time for the file.""" + last_write_time: Optional[Union[str, "datetime"]] = None + """Last write time for the file.""" + last_access_time: Optional["datetime"] = None + """Last access time for the file.""" + file_attributes: Union[str, NTFSAttributes] + """The file system attributes for files and directories.""" + permission_key: str + """Key of the permission to be set for the directory/file.""" + file_id: str + """FileId uniquely identifies the file or directory.""" + parent_id: str + """ParentId uniquely identifies the parent directory of the object.""" + is_directory: bool = True + """Whether input is a directory.""" + owner: Optional[str] = None + """NFS only. The owner of the directory.""" + group: Optional[str] = None + """NFS only. The owning group of the directory.""" + file_mode: Optional[str] = None + """NFS only. The file mode of the directory.""" + nfs_file_type: Optional[Literal['Directory']] = None + """NFS only. The type of the directory.""" + + def __init__(self, **kwargs: Any) -> None: + self.name = None # type: ignore [assignment] + self.last_modified = kwargs.get('Last-Modified') # type: ignore [assignment] + self.etag = kwargs.get('ETag') # type: ignore [assignment] + self.server_encrypted = kwargs.get('x-ms-server-encrypted') # type: ignore [assignment] + self.metadata = kwargs.get('metadata') # type: ignore [assignment] + self.change_time = _parse_datetime_from_str(kwargs.get('x-ms-file-change-time')) + self.creation_time = _parse_datetime_from_str(kwargs.get('x-ms-file-creation-time')) + self.last_write_time = _parse_datetime_from_str(kwargs.get('x-ms-file-last-write-time')) + self.last_access_time = None + self.file_attributes = kwargs.get('x-ms-file-attributes') # type: ignore [assignment] + self.permission_key = kwargs.get('x-ms-file-permission-key') # type: ignore [assignment] + self.file_id = kwargs.get('x-ms-file-id') # type: ignore [assignment] + self.parent_id = kwargs.get('x-ms-file-parent-id') # type: ignore [assignment] + self.is_directory = True + self.owner = kwargs.get('x-ms-owner') + self.group = kwargs.get('x-ms-group') + self.file_mode = kwargs.get('x-ms-mode') + self.nfs_file_type = kwargs.get('x-ms-file-file-type') + + @classmethod + def _from_generated(cls, generated): + props = cls() + props.name = unquote(generated.name.content) if generated.name.encoded else generated.name.content + props.file_id = generated.file_id + props.file_attributes = generated.attributes + props.last_modified = generated.properties.last_modified + props.creation_time = generated.properties.creation_time + props.last_access_time = generated.properties.last_access_time + props.last_write_time = generated.properties.last_write_time + props.change_time = generated.properties.change_time + props.etag = generated.properties.etag + props.permission_key = generated.permission_key + return props + + +class DirectoryPropertiesPaged(PageIterator): + """An iterable for the contents of a directory. + + This iterable will yield dicts for the contents of the directory. The dicts + will have the keys 'name' (str) and 'is_directory' (bool). + Items that are files (is_directory=False) will have an additional 'content_length' key. + + :param Callable command: Function to retrieve the next page of items. + :param Optional[str] prefix: Filters the results to return only directories whose names + begin with the specified prefix. + :param Optional[int] results_per_page: The maximum number of share names to retrieve per call. + :param Optional[str] continuation_token: An opaque continuation token. + """ + + service_endpoint: Optional[str] = None + """The service URL.""" + prefix: Optional[str] = None + """A file name prefix being used to filter the list.""" + marker: Optional[str] = None + """The continuation token of the current page of results.""" + results_per_page: Optional[int] = None + """The maximum number of results retrieved per API call.""" + continuation_token: Optional[str] = None + """The continuation token to retrieve the next page of results.""" + location_mode: Optional[str] = None + """The location mode being used to list results. The available options include "primary" and "secondary".""" + current_page: List[Dict[str, Any]] + """The current page of listed results.""" + + def __init__( + self, command: Callable, + prefix: Optional[str] = None, + results_per_page: Optional[int] = None, + continuation_token: Optional[str] = None + ) -> None: + super(DirectoryPropertiesPaged, self).__init__( + get_next=self._get_next_cb, + extract_data=self._extract_data_cb, + continuation_token=continuation_token or "" + ) + self._command = command + self.service_endpoint = None + self.prefix = prefix + self.marker = None + self.results_per_page = results_per_page + self.location_mode = None + self.current_page = [] + + def _get_next_cb(self, continuation_token): + try: + return self._command( + marker=continuation_token or None, + prefix=self.prefix, + maxresults=self.results_per_page, + cls=return_context_and_deserialized, + use_location=self.location_mode) + except HttpResponseError as error: + process_storage_error(error) + + def _extract_data_cb(self, get_next_return): + self.location_mode, self._response = get_next_return + self.service_endpoint = self._response.service_endpoint + self.prefix = self._response.prefix + self.marker = self._response.marker + self.results_per_page = self._response.max_results + self.current_page = [DirectoryProperties._from_generated(i) for i in self._response.segment.directory_items] # pylint: disable = protected-access + self.current_page.extend([FileProperties._from_generated(i) for i in self._response.segment.file_items]) # pylint: disable = protected-access + return self._response.next_marker or None, self.current_page + + +class CopyProperties(DictMixin): + """File Copy Properties. + + These properties will be `None` if this file has never been the destination in a Copy + File operation, or if this file has been modified after a concluded Copy File operation. + """ + + id: str + """String identifier for the last attempted Copy File operation where this file + was the destination file. This header does not appear if this file has never + been the destination in a Copy File operation, or if this file has been + modified after a concluded Copy File operation.""" + source: Optional[str] = None + """URL up to 2 KB in length that specifies the source file used in the last attempted + Copy File operation where this file was the destination file.""" + status: Optional[str] = None + """State of the copy operation identified by Copy ID, with these values: + success: + Copy completed successfully. + pending: + Copy is in progress. Check copy_status_description if intermittent, + non-fatal errors impede copy progress but don't cause failure. + aborted: + Copy was ended by Abort Copy File. + failed: + Copy failed. See copy_status_description for failure details.""" + progress: Optional[str] = None + """Contains the number of bytes copied and the total bytes in the source in the last + attempted Copy File operation where this file was the destination file. Can show + between 0 and Content-Length bytes copied.""" + status_description: Optional[str] = None + """Only appears when x-ms-copy-status is failed or pending. Describes cause of fatal + or non-fatal copy operation failure.""" + incremental_copy: Optional[bool] = None + """Copies the snapshot of the source file to a destination file. + The snapshot is copied such that only the differential changes between + the previously copied snapshot are transferred to the destination.""" + destination_snapshot: Optional["datetime"] = None + """Included if the file is incremental copy or incremental copy snapshot, + if x-ms-copy-status is success. Snapshot time of the last successful + incremental copy snapshot for this file.""" + datetime: Optional["datetime"] = None + """Conclusion time of the last attempted Copy File operation where this file was the + destination file. This value can specify the time of a completed, aborted, or + failed copy attempt.""" + + def __init__(self, **kwargs: Any) -> None: + self.id = kwargs.get('x-ms-copy-id') # type: ignore [assignment] + self.source = kwargs.get('x-ms-copy-source') + self.status = get_enum_value(kwargs.get('x-ms-copy-status')) + self.progress = kwargs.get('x-ms-copy-progress') + self.completion_time = kwargs.get('x-ms-copy-completion_time') + self.status_description = kwargs.get('x-ms-copy-status-description') + self.incremental_copy = kwargs.get('x-ms-incremental-copy') + self.destination_snapshot = kwargs.get('x-ms-copy-destination-snapshot') + + @classmethod + def _from_generated(cls, generated): + copy = cls() + copy.id = generated.properties.copy_id or None + copy.status = get_enum_value(generated.properties.copy_status) or None + copy.source = generated.properties.copy_source or None + copy.progress = generated.properties.copy_progress or None + copy.completion_time = generated.properties.copy_completion_time or None + copy.status_description = generated.properties.copy_status_description or None + copy.incremental_copy = generated.properties.incremental_copy or None + copy.destination_snapshot = generated.properties.destination_snapshot or None + return copy + + +class FileProperties(DictMixin): + """File's properties class.""" + + name: str + """The name of the file.""" + path: Optional[str] = None + """The path of the file.""" + share: Optional[str] = None + """The name of the share.""" + snapshot: Optional[str] = None + """File snapshot.""" + content_length: int + """Size of file in bytes.""" + metadata: Dict[str, str] + """Name-value pairs to associate with the file as metadata.""" + file_type: str + """String indicating the type of file.""" + last_modified: "datetime" + """A datetime object representing the last time the file was modified.""" + etag: str + """The ETag contains a value that can be used to perform operations conditionally.""" + size: int + """Size of the file in bytes.""" + content_range: Optional[str] = None + """Indicates the range of bytes returned in the event that the client + requested a subset of the file.""" + server_encrypted: bool + """Whether encryption is enabled.""" + copy: CopyProperties + """The copy properties.""" + content_settings: ContentSettings + """The content settings for the file.""" + lease: LeaseProperties + """File lease properties.""" + change_time: Optional[Union[str, "datetime"]] = None + """Change time for the file.""" + creation_time: Optional[Union[str, "datetime"]] = None + """Creation time for the file.""" + last_write_time: Optional[Union[str, "datetime"]] = None + """Last write time for the file.""" + last_access_time: Optional["datetime"] = None + """Last access time for the file.""" + file_attributes: Union[str, NTFSAttributes] + """The file system attributes for files and directories.""" + permission_key: str + """Key of the permission to be set for the directory/file.""" + file_id: str + """FileId uniquely identifies the file or directory.""" + parent_id: Optional[str] = None + """ParentId uniquely identifies the parent directory of the object.""" + is_directory: bool = False + """Whether input is a directory.""" + owner: Optional[str] = None + """NFS only. The owner of the file.""" + group: Optional[str] = None + """NFS only. The owning group of the file.""" + file_mode: Optional[str] = None + """NFS only. The file mode of the file.""" + link_count: Optional[int] = None + """NFS only. The number of hard links of the file.""" + nfs_file_type: Optional[Literal['Regular']] = None + """NFS only. The type of the file.""" + + def __init__(self, **kwargs: Any) -> None: + self.name = kwargs.get('name') # type: ignore [assignment] + self.path = None + self.share = None + self.snapshot = None + self.content_length = kwargs.get('Content-Length') # type: ignore [assignment] + self.metadata = kwargs.get('metadata') # type: ignore [assignment] + self.file_type = kwargs.get('x-ms-type') # type: ignore [assignment] + self.last_modified = kwargs.get('Last-Modified') # type: ignore [assignment] + self.etag = kwargs.get('ETag') # type: ignore [assignment] + self.size = kwargs.get('Content-Length') # type: ignore [assignment] + self.content_range = kwargs.get('Content-Range') + self.server_encrypted = kwargs.get('x-ms-server-encrypted') # type: ignore [assignment] + self.copy = CopyProperties(**kwargs) + self.content_settings = ContentSettings(**kwargs) + self.lease = LeaseProperties(**kwargs) + self.change_time = _parse_datetime_from_str(kwargs.get('x-ms-file-change-time')) + self.creation_time = _parse_datetime_from_str(kwargs.get('x-ms-file-creation-time')) + self.last_write_time = _parse_datetime_from_str(kwargs.get('x-ms-file-last-write-time')) + self.last_access_time = None + self.file_attributes = kwargs.get('x-ms-file-attributes') # type: ignore [assignment] + self.permission_key = kwargs.get('x-ms-file-permission-key') # type: ignore [assignment] + self.file_id = kwargs.get('x-ms-file-id') # type: ignore [assignment] + self.parent_id = kwargs.get('x-ms-file-parent-id') + self.is_directory = False + self.owner = kwargs.get('x-ms-owner') + self.group = kwargs.get('x-ms-group') + self.file_mode = kwargs.get('x-ms-mode') + self.link_count = kwargs.get('x-ms-link-count') + self.nfs_file_type = kwargs.get('x-ms-file-file-type') + + @classmethod + def _from_generated(cls, generated): + props = cls() + props.name = unquote(generated.name.content) if generated.name.encoded else generated.name.content + props.file_id = generated.file_id + props.etag = generated.properties.etag + props.file_attributes = generated.attributes + props.last_modified = generated.properties.last_modified + props.creation_time = generated.properties.creation_time + props.last_access_time = generated.properties.last_access_time + props.last_write_time = generated.properties.last_write_time + props.change_time = generated.properties.change_time + props.size = generated.properties.content_length + props.permission_key = generated.permission_key + return props + + +class ShareProtocols(str, Enum, metaclass=CaseInsensitiveEnumMeta): + """Enabled protocols on the share""" + SMB = "SMB" + NFS = "NFS" + + +class FileSasPermissions(object): + """FileSasPermissions class to be used with + generating shared access signature operations. + + :param bool read: + Read the content, properties, metadata. Use the file as the source of a copy operation. + :param bool create: + Create a new file or copy a file to a new file. + :param bool write: + Create or write content, properties, metadata. Resize the file. Use the file + as the destination of a copy operation within the same account. + :param bool delete: + Delete the file. + """ + + read: bool = False + """Read the content, properties, metadata. Use the file as the source of a copy operation.""" + create: bool = False + """Create a new file or copy a file to a new file.""" + write: bool = False + """Create or write content, properties, metadata. Resize the file. Use the file + as the destination of a copy operation within the same account.""" + delete: bool = False + """Delete the file.""" + + def __init__( + self, read: bool = False, + create: bool = False, + write: bool = False, + delete: bool = False + ) -> None: + self.read = read + self.create = create + self.write = write + self.delete = delete + self._str = (('r' if self.read else '') + + ('c' if self.create else '') + + ('w' if self.write else '') + + ('d' if self.delete else '')) + + def __str__(self): + return self._str + + @classmethod + def from_string(cls, permission: str) -> Self: + """Create a FileSasPermissions from a string. + + To specify read, create, write, or delete permissions you need only to + include the first letter of the word in the string. E.g. For read and + create permissions, you would provide a string "rc". + + :param str permission: The string which dictates the read, create, + write, or delete permissions + :return: A FileSasPermissions object + :rtype: ~azure.storage.fileshare.FileSasPermissions + """ + p_read = 'r' in permission + p_create = 'c' in permission + p_write = 'w' in permission + p_delete = 'd' in permission + + parsed = cls(p_read, p_create, p_write, p_delete) + + return parsed + + +def service_properties_deserialize(generated: GeneratedStorageServiceProperties) -> Dict[str, Any]: + return { + 'hour_metrics': Metrics._from_generated(generated.hour_metrics), # pylint: disable=protected-access + 'minute_metrics': Metrics._from_generated(generated.minute_metrics), # pylint: disable=protected-access + 'cors': [CorsRule._from_generated(cors) for cors in generated.cors], # type: ignore [union-attr] # pylint: disable=protected-access + 'protocol': ShareProtocolSettings._from_generated(generated.protocol), # pylint: disable=protected-access + } diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_parser.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_parser.py new file mode 100644 index 00000000..ed7c9488 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_parser.py @@ -0,0 +1,60 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from datetime import datetime, timedelta +from typing import Any, cast, Dict, Optional, Union + +from ._generated._serialization import Serializer + +_ERROR_TOO_MANY_FILE_PERMISSIONS = 'file_permission and file_permission_key should not be set at the same time' +_FILE_PERMISSION_TOO_LONG = 'Size of file_permission is too large. file_permission should be <=8KB, else' \ + 'please use file_permission_key' + + +def _get_file_permission(file_permission, file_permission_key, default_permission): + # if file_permission and file_permission_key are both empty, then use the default_permission + # value as file permission, file_permission size should be <= 8KB, else file permission_key should be used + if file_permission and len(str(file_permission).encode('utf-8')) > 8 * 1024: + raise ValueError(_FILE_PERMISSION_TOO_LONG) + + if not file_permission: + if not file_permission_key: + return default_permission + return None + + if not file_permission_key: + return file_permission + + raise ValueError(_ERROR_TOO_MANY_FILE_PERMISSIONS) + + +def _parse_datetime_from_str(string_datetime): + if not string_datetime: + return None + dt, _, us = string_datetime.partition(".") + dt = datetime.strptime(dt, "%Y-%m-%dT%H:%M:%S") + us = int(us[:-2]) # microseconds + datetime_obj = dt + timedelta(microseconds=us) + return datetime_obj + + +def _datetime_to_str(datetime_obj): + if not datetime_obj: + return None + if isinstance(datetime_obj, str): + return datetime_obj + return Serializer.serialize_iso(datetime_obj)[:-1].ljust(27, "0") + "Z" + + +def _parse_snapshot( + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + path_snapshot: Optional[str] = None +) -> Optional[str]: + if hasattr(snapshot, 'snapshot'): + return snapshot.snapshot # type: ignore + if isinstance(snapshot, Dict): + return cast(str, snapshot['snapshot']) + return snapshot or path_snapshot diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_serialize.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_serialize.py new file mode 100644 index 00000000..4f989315 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_serialize.py @@ -0,0 +1,195 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from typing import Any, Dict, Optional, Tuple, Union, TYPE_CHECKING + +from azure.core import MatchConditions + +from ._parser import _datetime_to_str, _get_file_permission +from ._generated.models import ( + SourceModifiedAccessConditions, + LeaseAccessConditions, + SourceLeaseAccessConditions, + DestinationLeaseAccessConditions, + CopyFileSmbInfo +) + +if TYPE_CHECKING: + from ._lease import ShareLeaseClient + from .aio._lease_async import ShareLeaseClient as ShareLeaseClientAsync + + +_SUPPORTED_API_VERSIONS = [ + '2019-02-02', + '2019-07-07', + '2019-10-10', + '2019-12-12', + '2020-02-10', + '2020-04-08', + '2020-06-12', + '2020-08-04', + '2020-10-02', + '2020-12-06', + '2021-02-12', + '2021-04-10', + '2021-06-08', + '2021-08-06', + '2021-12-02', + '2022-11-02', + '2023-01-03', + '2023-05-03', + '2023-08-03', + '2023-11-03', + '2024-05-04', + '2024-08-04', + '2024-11-04', + '2025-01-05', + '2025-05-05', +] + + +def _get_match_headers( + kwargs: Dict[str, Any], + match_param: str, + etag_param: str +) -> Tuple[Optional[str], Optional[str]]: + if_match = None + if_none_match = None + match_condition = kwargs.pop(match_param, None) + if match_condition == MatchConditions.IfNotModified: + if_match = kwargs.pop(etag_param, None) + if not if_match: + raise ValueError(f"'{match_param}' specified without '{etag_param}'.") + elif match_condition == MatchConditions.IfPresent: + if_match = '*' + elif match_condition == MatchConditions.IfModified: + if_none_match = kwargs.pop(etag_param, None) + if not if_none_match: + raise ValueError(f"'{match_param}' specified without '{etag_param}'.") + elif match_condition == MatchConditions.IfMissing: + if_none_match = '*' + elif match_condition is None: + if etag_param in kwargs: + raise ValueError(f"'{etag_param}' specified without '{match_param}'.") + else: + raise TypeError(f"Invalid match condition: {match_condition}") + return if_match, if_none_match + + +def get_source_conditions(kwargs: Dict[str, Any]) -> SourceModifiedAccessConditions: + if_match, if_none_match = _get_match_headers(kwargs, 'source_match_condition', 'source_etag') + return SourceModifiedAccessConditions( + source_if_modified_since=kwargs.pop('source_if_modified_since', None), + source_if_unmodified_since=kwargs.pop('source_if_unmodified_since', None), + source_if_match=if_match or kwargs.pop('source_if_match', None), + source_if_none_match=if_none_match or kwargs.pop('source_if_none_match', None) + ) + + +def get_access_conditions( + lease: Optional[Union["ShareLeaseClient", "ShareLeaseClientAsync", str]] +) -> Optional[LeaseAccessConditions]: + if lease is None: + return None + if hasattr(lease, "id"): + lease_id = lease.id + else: + lease_id = lease + return LeaseAccessConditions(lease_id=lease_id) + + +def get_source_access_conditions( + lease: Optional[Union["ShareLeaseClient", "ShareLeaseClientAsync", str]] +) -> Optional[SourceLeaseAccessConditions]: + if lease is None: + return None + if hasattr(lease, "id"): + lease_id = lease.id + else: + lease_id = lease + return SourceLeaseAccessConditions(source_lease_id=lease_id) + + +def get_dest_access_conditions( + lease: Optional[Union["ShareLeaseClient", "ShareLeaseClientAsync", str]] +) -> Optional[DestinationLeaseAccessConditions]: + if lease is None: + return None + if hasattr(lease, "id"): + lease_id = lease.id + else: + lease_id = lease + return DestinationLeaseAccessConditions(destination_lease_id=lease_id) + + +def get_smb_properties(kwargs: Dict[str, Any]) -> Dict[str, Any]: + ignore_read_only = kwargs.pop('ignore_read_only', None) + set_archive_attribute = kwargs.pop('set_archive_attribute', None) + file_permission = kwargs.pop('file_permission', None) + file_permission_key = kwargs.pop('permission_key', None) + file_attributes = kwargs.pop('file_attributes', None) + file_creation_time = kwargs.pop('file_creation_time', None) + file_last_write_time = kwargs.pop('file_last_write_time', None) + file_change_time = kwargs.pop('file_change_time', None) + + file_permission_copy_mode = None + file_permission = _get_file_permission(file_permission, file_permission_key, None) + + if file_permission: + if file_permission.lower() == "source": + file_permission = None + file_permission_copy_mode = "source" + else: + file_permission_copy_mode = "override" + elif file_permission_key: + if file_permission_key.lower() == "source": + file_permission_key = None + file_permission_copy_mode = "source" + else: + file_permission_copy_mode = "override" + return { + 'file_permission': file_permission, + 'file_permission_key': file_permission_key, + 'copy_file_smb_info': CopyFileSmbInfo( + file_permission_copy_mode=file_permission_copy_mode, + ignore_read_only=ignore_read_only, + file_attributes=file_attributes, + file_creation_time=_datetime_to_str(file_creation_time), + file_last_write_time=_datetime_to_str(file_last_write_time), + file_change_time=_datetime_to_str(file_change_time), + set_archive_attribute=set_archive_attribute + ) + + } + + +def get_rename_smb_properties(kwargs: Dict[str, Any]) -> Dict[str, Any]: + file_permission = kwargs.pop('file_permission', None) + file_permission_key = kwargs.pop('permission_key', None) + file_attributes = kwargs.pop('file_attributes', None) + file_creation_time = kwargs.pop('file_creation_time', None) + file_last_write_time = kwargs.pop('file_last_write_time', None) + file_change_time = kwargs.pop('file_change_time', None) + + file_permission = _get_file_permission(file_permission, file_permission_key, None) + + return { + 'file_permission': file_permission, + 'file_permission_key': file_permission_key, + 'copy_file_smb_info': CopyFileSmbInfo( + file_attributes=file_attributes, + file_creation_time=_datetime_to_str(file_creation_time), + file_last_write_time=_datetime_to_str(file_last_write_time), + file_change_time=_datetime_to_str(file_change_time) + )} + + +def get_api_version(kwargs: Dict[str, Any]) -> str: + api_version = kwargs.get('api_version', None) + if api_version and api_version not in _SUPPORTED_API_VERSIONS: + versions = '\n'.join(_SUPPORTED_API_VERSIONS) + raise ValueError(f"Unsupported API version '{api_version}'. Please select from:\n{versions}") + return api_version or _SUPPORTED_API_VERSIONS[-1] diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_share_client.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_share_client.py new file mode 100644 index 00000000..602757dd --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_share_client.py @@ -0,0 +1,995 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=docstring-keyword-should-match-keyword-only + +from typing import ( + Any, cast, Dict, Literal, Optional, Union, + TYPE_CHECKING +) +from typing_extensions import Self + +from azure.core.exceptions import HttpResponseError +from azure.core.paging import ItemPaged +from azure.core.pipeline import Pipeline +from azure.core.tracing.decorator import distributed_trace +from ._deserialize import deserialize_permission, deserialize_share_properties +from ._directory_client import ShareDirectoryClient +from ._file_client import ShareFileClient +from ._generated import AzureFileStorage +from ._generated.models import ( + DeleteSnapshotsOptionType, + ShareStats, + SignedIdentifier +) +from ._lease import ShareLeaseClient +from ._models import ShareProtocols +from ._parser import _parse_snapshot +from ._serialize import get_access_conditions, get_api_version +from ._share_client_helpers import ( + _create_permission_for_share_options, + _format_url, + _from_share_url, + _parse_url +) +from ._shared.base_client import parse_connection_str, parse_query, StorageAccountHostsMixin, TransportWrapper +from ._shared.request_handlers import add_metadata_headers, serialize_iso +from ._shared.response_handlers import ( + process_storage_error, + return_headers_and_deserialized, + return_response_headers +) + + +if TYPE_CHECKING: + from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential, TokenCredential + from ._models import AccessPolicy, DirectoryProperties, FileProperties, ShareProperties + + +class ShareClient(StorageAccountHostsMixin): + """A client to interact with a specific share, although that share may not yet exist. + + For operations relating to a specific directory or file in this share, the clients for + those entities can also be retrieved using the :func:`get_directory_client` and :func:`get_file_client` functions. + + For more optional configuration, please click + `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #optional-configuration>`__. + + :param str account_url: + The URI to the storage account. In order to create a client given the full URI to the share, + use the :func:`from_share_url` classmethod. + :param share_name: + The name of the share with which to interact. + :type share_name: str + :param str snapshot: + An optional share snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`create_snapshot`. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a TokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials.TokenCredential or + str or dict[str, str] or None + :keyword token_intent: + Required when using `TokenCredential` for authentication and ignored for other forms of authentication. + Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are: + + backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory + ACLs are bypassed and full permissions are granted. User must also have required RBAC permission. + + :paramtype token_intent: Literal['backup'] + :keyword bool allow_trailing_dot: If true, the trailing dot will not be trimmed from the target URI. + :keyword bool allow_source_trailing_dot: If true, the trailing dot will not be trimmed from the source URI. + :keyword str api_version: + The Storage API version to use for requests. Default value is the most recent service version that is + compatible with the current SDK. Setting to an older version may result in reduced feature compatibility. + + .. versionadded:: 12.1.0 + + :keyword str secondary_hostname: + The hostname of the secondary endpoint. + :keyword int max_range_size: The maximum range size used for a file upload. Defaults to 4*1024*1024. + """ + def __init__( + self, account_url: str, + share_name: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long + *, + token_intent: Optional[Literal['backup']] = None, + **kwargs: Any + ) -> None: + if hasattr(credential, 'get_token') and not token_intent: + raise ValueError("'token_intent' keyword is required when 'credential' is an TokenCredential.") + parsed_url = _parse_url(account_url, share_name) + path_snapshot, sas_token = parse_query(parsed_url.query) + if not sas_token and not credential: + raise ValueError( + 'You need to provide either an account shared key or SAS token when creating a storage service.') + self.snapshot = _parse_snapshot(snapshot, path_snapshot) + self.share_name = share_name + self._query_str, credential = self._format_query_string( + sas_token=sas_token, credential=credential, share_snapshot=self.snapshot) + super(ShareClient, self).__init__( + parsed_url=parsed_url, service='file-share', credential=credential, **kwargs) + self.allow_trailing_dot = kwargs.pop('allow_trailing_dot', None) + self.allow_source_trailing_dot = kwargs.pop('allow_source_trailing_dot', None) + self.file_request_intent = token_intent + self._client = AzureFileStorage(url=self.url, base_url=self.url, pipeline=self._pipeline, + allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, + file_request_intent=self.file_request_intent) + self._client._config.version = get_api_version(kwargs) # type: ignore [assignment] + + @classmethod + def from_share_url( + cls, share_url: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """ + :param str share_url: The full URI to the share. + :param snapshot: + An optional share snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`create_snapshot`. + :type snapshot: Optional[Union[str, dict[str, Any]]] + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a TokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials.TokenCredential or + str or dict[str, str] or None + :returns: A share client. + :rtype: ~azure.storage.fileshare.ShareClient + """ + account_url, share_name, path_snapshot = _from_share_url(share_url, snapshot) + return cls(account_url, share_name, path_snapshot, credential, **kwargs) + + def _format_url(self, hostname: str) -> str: + """Format the endpoint URL according to the current location mode hostname. + + :param str hostname: + The hostname of the current location mode. + :returns: A formatted endpoint URL including current location mode hostname. + :rtype: str + """ + return _format_url(self.scheme, hostname, self.share_name, self._query_str) + + @classmethod + def from_connection_string( + cls, conn_str: str, + share_name: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """Create ShareClient from a Connection String. + + :param str conn_str: + A connection string to an Azure Storage account. + :param str share_name: The name of the share. + :param snapshot: + The optional share snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`create_snapshot`. + :type snapshot: Optional[Union[str, dict[str, Any]]] + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a TokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials.TokenCredential or + str or dict[str, str] or None + :returns: A share client. + :rtype: ~azure.storage.fileshare.ShareClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share.py + :start-after: [START create_share_client_from_conn_string] + :end-before: [END create_share_client_from_conn_string] + :language: python + :dedent: 8 + :caption: Gets the share client from connection string. + """ + account_url, secondary, credential = parse_connection_str(conn_str, credential, 'file') + if 'secondary_hostname' not in kwargs: + kwargs['secondary_hostname'] = secondary + return cls( + account_url, share_name=share_name, snapshot=snapshot, credential=credential, **kwargs) + + def get_directory_client(self, directory_path: Optional[str] = None) -> ShareDirectoryClient: + """Get a client to interact with the specified directory. + The directory need not already exist. + + :param str directory_path: + Path to the specified directory. + :returns: A Directory Client. + :rtype: ~azure.storage.fileshare.ShareDirectoryClient + """ + _pipeline = Pipeline( + transport=TransportWrapper(self._pipeline._transport), # pylint: disable=protected-access + policies=self._pipeline._impl_policies # pylint: disable=protected-access + ) + + return ShareDirectoryClient( + self.url, share_name=self.share_name, directory_path=directory_path or "", snapshot=self.snapshot, + credential=self.credential, token_intent=self.file_request_intent, api_version=self.api_version, + _hosts=self._hosts, _configuration=self._config, _pipeline=_pipeline, + _location_mode=self._location_mode, allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot) + + def get_file_client(self, file_path: str) -> ShareFileClient: + """Get a client to interact with the specified file. + The file need not already exist. + + :param str file_path: + Path to the specified file. + :returns: A File Client. + :rtype: ~azure.storage.fileshare.ShareFileClient + """ + _pipeline = Pipeline( + transport=TransportWrapper(self._pipeline._transport), # pylint: disable=protected-access + policies=self._pipeline._impl_policies # pylint: disable=protected-access + ) + + return ShareFileClient( + self.url, share_name=self.share_name, file_path=file_path, snapshot=self.snapshot, + credential=self.credential, token_intent=self.file_request_intent, api_version=self.api_version, + _hosts=self._hosts, _configuration=self._config, + _pipeline=_pipeline, _location_mode=self._location_mode, allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot) + + @distributed_trace + def acquire_lease(self, **kwargs: Any) -> ShareLeaseClient: + """Requests a new lease. + + If the share does not have an active lease, the Share + Service creates a lease on the share and returns a new lease. + + .. versionadded:: 12.5.0 + + :keyword int lease_duration: + Specifies the duration of the lease, in seconds, or negative one + (-1) for a lease that never expires. A non-infinite lease can be + between 15 and 60 seconds. A lease duration cannot be changed + using renew or change. Default is -1 (infinite lease). + :keyword str lease_id: + Proposed lease ID, in a GUID string format. The Share Service + returns 400 (Invalid request) if the proposed lease ID is not + in the correct format. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: A ShareLeaseClient object. + :rtype: ~azure.storage.fileshare.ShareLeaseClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share.py + :start-after: [START acquire_and_release_lease_on_share] + :end-before: [END acquire_and_release_lease_on_share] + :language: python + :dedent: 8 + :caption: Acquiring a lease on a share. + """ + kwargs['lease_duration'] = kwargs.pop('lease_duration', -1) + lease_id = kwargs.pop('lease_id', None) + lease = ShareLeaseClient(self, lease_id=lease_id) + lease.acquire(**kwargs) + return lease + + @distributed_trace + def create_share(self, **kwargs: Any) -> Dict[str, Any]: + """Creates a new Share under the account. If a share with the + same name already exists, the operation fails. + + :keyword metadata: + Name-value pairs associated with the share as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword int quota: + The quota to be allotted. + :keyword access_tier: + Specifies the access tier of the share. + Possible values: 'TransactionOptimized', 'Hot', 'Cool', 'Premium' + :paramtype access_tier: str or ~azure.storage.fileshare.models.ShareAccessTier + + .. versionadded:: 12.4.0 + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword protocols: + Protocols to enable on the share. Only one protocol can be enabled on the share. + :paramtype protocols: str or ~azure.storage.fileshare.ShareProtocols + :keyword root_squash: + Root squash to set on the share. + Only valid for NFS shares. Possible values include: 'NoRootSquash', 'RootSquash', 'AllSquash'. + :paramtype root_squash: str or ~azure.storage.fileshare.ShareRootSquash + :keyword bool paid_bursting_enabled: This property enables paid bursting. + :keyword int paid_bursting_bandwidth_mibps: The maximum throughput the file share can support in MiB/s. + :keyword int paid_bursting_iops: The maximum IOPS the file share can support. + :keyword int provisioned_iops: The provisioned IOPS of the share, stored on the share object. + :keyword int provisioned_bandwidth_mibps: The provisioned throughput of the share, stored on the share object. + :returns: Share-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share.py + :start-after: [START create_share] + :end-before: [END create_share] + :language: python + :dedent: 8 + :caption: Creates a file share. + """ + metadata = kwargs.pop('metadata', None) + quota = kwargs.pop('quota', None) + access_tier = kwargs.pop('access_tier', None) + timeout = kwargs.pop('timeout', None) + root_squash = kwargs.pop('root_squash', None) + protocols = kwargs.pop('protocols', None) + paid_bursting_bandwidth_mibps = kwargs.pop('paid_bursting_bandwidth_mibps', None) + paid_bursting_iops = kwargs.pop('paid_bursting_iops', None) + share_provisioned_iops = kwargs.pop('provisioned_iops', None) + share_provisioned_bandwidth_mibps = kwargs.pop('provisioned_bandwidth_mibps', None) + if protocols and protocols not in ['NFS', 'SMB', ShareProtocols.SMB, ShareProtocols.NFS]: + raise ValueError("The enabled protocol must be set to either SMB or NFS.") + if root_squash and protocols not in ['NFS', ShareProtocols.NFS]: + raise ValueError("The 'root_squash' keyword can only be used on NFS enabled shares.") + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + + try: + return cast(Dict[str, Any], self._client.share.create( + timeout=timeout, + metadata=metadata, + quota=quota, + access_tier=access_tier, + root_squash=root_squash, + enabled_protocols=protocols, + paid_bursting_max_bandwidth_mibps=paid_bursting_bandwidth_mibps, + paid_bursting_max_iops=paid_bursting_iops, + share_provisioned_iops=share_provisioned_iops, + share_provisioned_bandwidth_mibps=share_provisioned_bandwidth_mibps, + cls=return_response_headers, + headers=headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def create_snapshot(self, **kwargs: Any) -> Dict[str, Any]: + """Creates a snapshot of the share. + + A snapshot is a read-only version of a share that's taken at a point in time. + It can be read, copied, or deleted, but not modified. Snapshots provide a way + to back up a share as it appears at a moment in time. + + A snapshot of a share has the same name as the base share from which the snapshot + is taken, with a DateTime value appended to indicate the time at which the + snapshot was taken. + + :keyword metadata: + Name-value pairs associated with the share as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: Share-updated property dict (Snapshot ID, Etag, and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share.py + :start-after: [START create_share_snapshot] + :end-before: [END create_share_snapshot] + :language: python + :dedent: 12 + :caption: Creates a snapshot of the file share. + """ + metadata = kwargs.pop('metadata', None) + timeout = kwargs.pop('timeout', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + try: + return cast(Dict[str, Any], self._client.share.create_snapshot( + timeout=timeout, + cls=return_response_headers, + headers=headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def delete_share( + self, delete_snapshots: Optional[Union[bool, Literal['include', 'include-leased']]] = False, + **kwargs: Any + ) -> None: + """Marks the specified share for deletion. The share is + later deleted during garbage collection. + + :param delete_snapshots: + Indicates if snapshots are to be deleted. If "True" or enum "include", snapshots will + be deleted (but not include leased). To include leased snapshots, specify the "include-leased" + enum. + :type delete_snapshots: + Optional[Union[bool, Literal['include', 'include-leased']]] + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share.py + :start-after: [START delete_share] + :end-before: [END delete_share] + :language: python + :dedent: 12 + :caption: Deletes the share and any snapshots. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + delete_include = None + if isinstance(delete_snapshots, bool) and delete_snapshots: + delete_include = DeleteSnapshotsOptionType.INCLUDE + else: + if delete_snapshots == 'include': + delete_include = DeleteSnapshotsOptionType.INCLUDE + elif delete_snapshots == 'include-leased': + delete_include = DeleteSnapshotsOptionType.INCLUDE_LEASED + try: + self._client.share.delete( + timeout=timeout, + sharesnapshot=self.snapshot, + lease_access_conditions=access_conditions, + delete_snapshots=delete_include, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def get_share_properties(self, **kwargs: Any) -> "ShareProperties": + """Returns all user-defined metadata and system properties for the + specified share. The data returned does not include the shares's + list of files or directories. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + :returns: The share properties. + :rtype: ~azure.storage.fileshare.ShareProperties + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_hello_world.py + :start-after: [START get_share_properties] + :end-before: [END get_share_properties] + :language: python + :dedent: 12 + :caption: Gets the share properties. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + props = cast("ShareProperties", self._client.share.get_properties( + timeout=timeout, + sharesnapshot=self.snapshot, + cls=deserialize_share_properties, + lease_access_conditions=access_conditions, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + props.name = self.share_name + props.snapshot = self.snapshot + return props + + @distributed_trace + def set_share_quota(self, quota: int, **kwargs: Any) -> Dict[str, Any]: + """Sets the quota for the share. + + :param int quota: + Specifies the maximum size of the share, in gigabytes. + Must be greater than 0, and less than or equal to 5TB. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + :returns: Share-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share.py + :start-after: [START set_share_quota] + :end-before: [END set_share_quota] + :language: python + :dedent: 12 + :caption: Sets the share quota. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + return cast(Dict[str, Any], self._client.share.set_properties( + timeout=timeout, + quota=quota, + access_tier=None, + lease_access_conditions=access_conditions, + cls=return_response_headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def set_share_properties(self, **kwargs: Any) -> Dict[str, Any]: + """Sets the share properties. + + .. versionadded:: 12.4.0 + + :keyword access_tier: + Specifies the access tier of the share. + Possible values: 'TransactionOptimized', 'Hot', 'Cool', 'Premium' + :paramtype access_tier: str or ~azure.storage.fileshare.models.ShareAccessTier + :keyword int quota: + Specifies the maximum size of the share, in gigabytes. + Must be greater than 0, and less than or equal to 5TB. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword root_squash: + Root squash to set on the share. + Only valid for NFS shares. Possible values include: 'NoRootSquash', 'RootSquash', 'AllSquash'. + :paramtype root_squash: str or ~azure.storage.fileshare.ShareRootSquash + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + :keyword bool paid_bursting_enabled: This property enables paid bursting. + :keyword int paid_bursting_bandwidth_mibps: The maximum throughput the file share can support in MiB/s. + :keyword int paid_bursting_iops: The maximum IOPS the file share can support. + :keyword int provisioned_iops: The provisioned IOPS of the share, stored on the share object. + :keyword int provisioned_bandwidth_mibps: The provisioned throughput of the share, stored on the share object. + :returns: Share-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share.py + :start-after: [START set_share_properties] + :end-before: [END set_share_properties] + :language: python + :dedent: 12 + :caption: Sets the share properties. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + access_tier = kwargs.pop('access_tier', None) + quota = kwargs.pop('quota', None) + root_squash = kwargs.pop('root_squash', None) + paid_bursting_bandwidth_mibps = kwargs.pop('paid_bursting_bandwidth_mibps', None) + paid_bursting_iops = kwargs.pop('paid_bursting_iops', None) + share_provisioned_iops = kwargs.pop('provisioned_iops', None) + share_provisioned_bandwidth_mibps = kwargs.pop('provisioned_bandwidth_mibps', None) + if all(parameter is None for parameter in [access_tier, quota, root_squash]): + raise ValueError("set_share_properties should be called with at least one parameter.") + try: + return cast(Dict[str, Any], self._client.share.set_properties( + timeout=timeout, + quota=quota, + access_tier=access_tier, + root_squash=root_squash, + lease_access_conditions=access_conditions, + paid_bursting_max_bandwidth_mibps=paid_bursting_bandwidth_mibps, + paid_bursting_max_iops=paid_bursting_iops, + share_provisioned_iops=share_provisioned_iops, + share_provisioned_bandwidth_mibps=share_provisioned_bandwidth_mibps, + cls=return_response_headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def set_share_metadata(self, metadata: Dict[str, str], **kwargs: Any) -> Dict[str, Any]: + """Sets the metadata for the share. + + Each call to this operation replaces all existing metadata + attached to the share. To remove all metadata from the share, + call this operation with no metadata dict. + + :param metadata: + Name-value pairs associated with the share as metadata. + :type metadata: dict[str, str] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + :returns: Share-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share.py + :start-after: [START set_share_metadata] + :end-before: [END set_share_metadata] + :language: python + :dedent: 12 + :caption: Sets the share metadata. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + try: + return cast(Dict[str, Any], self._client.share.set_metadata( + timeout=timeout, + cls=return_response_headers, + headers=headers, + lease_access_conditions=access_conditions, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def get_share_access_policy(self, **kwargs: Any) -> Dict[str, Any]: + """Gets the permissions for the share. The permissions + indicate whether files in a share may be accessed publicly. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + :returns: Access policy information in a dict. + :rtype: dict[str, Any] + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + response, identifiers = self._client.share.get_access_policy( + timeout=timeout, + cls=return_headers_and_deserialized, + lease_access_conditions=access_conditions, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + return { + 'public_access': response.get('share_public_access'), + 'signed_identifiers': identifiers or [] + } + + @distributed_trace + def set_share_access_policy(self, signed_identifiers: Dict[str, "AccessPolicy"], **kwargs: Any) -> Dict[str, Any]: + """Sets the permissions for the share, or stored access + policies that may be used with Shared Access Signatures. The permissions + indicate whether files in a share may be accessed publicly. + + :param signed_identifiers: + A dictionary of access policies to associate with the share. The + dictionary may contain up to 5 elements. An empty dictionary + will clear the access policies set on the service. + :type signed_identifiers: dict[str, ~azure.storage.fileshare.AccessPolicy] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + :returns: Share-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + if len(signed_identifiers) > 5: + raise ValueError( + 'Too many access policies provided. The server does not support setting ' + 'more than 5 access policies on a single resource.') + identifiers = [] + for key, value in signed_identifiers.items(): + if value: + value.start = serialize_iso(value.start) + value.expiry = serialize_iso(value.expiry) + identifiers.append(SignedIdentifier(id=key, access_policy=value)) + try: + return cast(Dict[str, Any], self._client.share.set_access_policy( + share_acl=identifiers or None, + timeout=timeout, + cls=return_response_headers, + lease_access_conditions=access_conditions, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def get_share_stats(self, **kwargs: Any) -> int: + """Gets the approximate size of the data stored on the share in bytes. + + Note that this value may not include all recently created + or recently re-sized files. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + :return: The approximate size of the data (in bytes) stored on the share. + :rtype: int + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + stats = cast(ShareStats, self._client.share.get_statistics( + timeout=timeout, + lease_access_conditions=access_conditions, + **kwargs)) + return stats.share_usage_bytes + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def list_directories_and_files( + self, directory_name: Optional[str] = None, + name_starts_with: Optional[str] = None, + marker: Optional[str] = None, + **kwargs: Any + ) -> ItemPaged[Union["DirectoryProperties", "FileProperties"]]: + """Lists the directories and files under the share. + + :param str directory_name: + Name of a directory. + :param str name_starts_with: + Filters the results to return only directories whose names + begin with the specified prefix. + :param str marker: + An opaque continuation token. This value can be retrieved from the + next_marker field of a previous generator object. If specified, + this generator will begin returning results from this point. + :keyword List[str] include: + Include this parameter to specify one or more datasets to include in the response. + Possible str values are "timestamps", "Etag", "Attributes", "PermissionKey". + + .. versionadded:: 12.6.0 + + This keyword argument was introduced in API version '2020-10-02'. + + :keyword bool include_extended_info: + If this is set to true, file id will be returned in listed results. + + .. versionadded:: 12.6.0 + + This keyword argument was introduced in API version '2020-10-02'. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: An auto-paging iterable of dict-like DirectoryProperties and FileProperties + :rtype: ~azure.core.paging.ItemPaged[Union[DirectoryProperties, FileProperties]] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share.py + :start-after: [START share_list_files_in_dir] + :end-before: [END share_list_files_in_dir] + :language: python + :dedent: 12 + :caption: List directories and files in the share. + """ + timeout = kwargs.pop('timeout', None) + directory = self.get_directory_client(directory_name) + kwargs.setdefault('merge_span', True) + return directory.list_directories_and_files( + name_starts_with=name_starts_with, marker=marker, timeout=timeout, **kwargs) + + @distributed_trace + def create_permission_for_share(self, file_permission: str, **kwargs: Any) -> Optional[str]: + """Create a permission (a security descriptor) at the share level. + + This 'permission' can be used for the files/directories in the share. + If a 'permission' already exists, it shall return the key of it, else + creates a new permission at the share level and return its key. + + :param str file_permission: + File permission, a Portable SDDL + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :returns: A file permission key + :rtype: str or None + """ + timeout = kwargs.pop('timeout', None) + options = _create_permission_for_share_options(file_permission, timeout=timeout, **kwargs) + try: + return cast(Optional[str], self._client.share.create_permission(**options)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def get_permission_for_share(self, permission_key: str, **kwargs: Any) -> str: + """Get a permission (a security descriptor) for a given key. + + This 'permission' can be used for the files/directories in the share. + + :param str permission_key: + Key of the file permission to retrieve + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :returns: A file permission (a portable SDDL) + :rtype: str + """ + timeout = kwargs.pop('timeout', None) + try: + return cast(str, self._client.share.get_permission( + file_permission_key=permission_key, + cls=deserialize_permission, + timeout=timeout, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def create_directory(self, directory_name: str, **kwargs: Any) -> ShareDirectoryClient: + """Creates a directory in the share and returns a client to interact + with the directory. + + :param str directory_name: + The name of the directory. + :keyword metadata: + Name-value pairs associated with the directory as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword str owner: + NFS only. The owner of the directory. + :keyword str group: + NFS only. The owning group of the directory. + :keyword str file_mode: + NFS only. The file mode of the directory. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: ShareDirectoryClient + :rtype: ~azure.storage.fileshare.ShareDirectoryClient + """ + directory = self.get_directory_client(directory_name) + kwargs.setdefault('merge_span', True) + directory.create_directory(**kwargs) + return directory + + @distributed_trace + def delete_directory(self, directory_name: str, **kwargs: Any) -> None: + """Marks the directory for deletion. The directory is + later deleted during garbage collection. + + :param str directory_name: + The name of the directory. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + """ + directory = self.get_directory_client(directory_name) + directory.delete_directory(**kwargs) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_share_client_helpers.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_share_client_helpers.py new file mode 100644 index 00000000..7d3f041d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_share_client_helpers.py @@ -0,0 +1,75 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from typing import ( + Any, Dict, Optional, Tuple, Union, + TYPE_CHECKING +) +from urllib.parse import quote, unquote, urlparse + +from ._deserialize import deserialize_permission_key +from ._generated.models import SharePermission +from ._parser import _parse_snapshot +from ._shared.base_client import parse_query + +if TYPE_CHECKING: + from urllib.parse import ParseResult + + +def _parse_url(account_url: str, share_name: str) -> "ParseResult": + try: + if not account_url.lower().startswith('http'): + account_url = "https://" + account_url + except AttributeError as exc: + raise ValueError("Account URL must be a string.") from exc + parsed_url = urlparse(account_url.rstrip('/')) + if not share_name: + raise ValueError("Please specify a share name.") + if not parsed_url.netloc: + raise ValueError(f"Invalid URL: {account_url}") + return parsed_url + + +def _format_url(scheme: str, hostname: str, share_name: Union[str, bytes], query_str: str) -> str: + if isinstance(share_name, str): + share_name = share_name.encode('UTF-8') + return f"{scheme}://{hostname}/{quote(share_name)}{query_str}" + + +def _from_share_url(share_url: str, snapshot: Optional[Union[str, Dict[str, Any]]]) -> Tuple[str, str, Optional[str]]: + try: + if not share_url.lower().startswith('http'): + share_url = "https://" + share_url + except AttributeError as exc: + raise ValueError("Share URL must be a string.") from exc + parsed_url = urlparse(share_url.rstrip('/')) + if not (parsed_url.path and parsed_url.netloc): + raise ValueError(f"Invalid URL: {share_url}") + + share_path = parsed_url.path.lstrip('/').split('/') + account_path = "" + if len(share_path) > 1: + account_path = "/" + "/".join(share_path[:-1]) + account_url = f"{parsed_url.scheme}://{parsed_url.netloc.rstrip('/')}{account_path}?{parsed_url.query}" + + share_name = unquote(share_path[-1]) + path_snapshot, _ = parse_query(parsed_url.query) + path_snapshot = _parse_snapshot(snapshot, path_snapshot) + + if not share_name: + raise ValueError("Invalid URL. Please provide a URL with a valid share name") + + return account_url, share_name, path_snapshot + + +def _create_permission_for_share_options(file_permission: str, **kwargs: Any) -> Dict[str, Any]: + options = { + 'share_permission': SharePermission(permission=file_permission), + 'cls': deserialize_permission_key, + 'timeout': kwargs.pop('timeout', None), + } + options.update(kwargs) + return options diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_share_service_client.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_share_service_client.py new file mode 100644 index 00000000..4ef878f9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_share_service_client.py @@ -0,0 +1,489 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=docstring-keyword-should-match-keyword-only + +import sys +import functools +from typing import ( + Union, Optional, Any, Dict, List, + TYPE_CHECKING +) +from typing_extensions import Self + +from azure.core.exceptions import HttpResponseError +from azure.core.paging import ItemPaged +from azure.core.pipeline import Pipeline +from azure.core.tracing.decorator import distributed_trace +from ._generated import AzureFileStorage +from ._generated.models import StorageServiceProperties +from ._models import ( + CorsRule, + ShareProperties, + SharePropertiesPaged, + service_properties_deserialize, +) +from ._serialize import get_api_version +from ._share_client import ShareClient +from ._share_service_client_helpers import _parse_url +from ._shared.base_client import StorageAccountHostsMixin, TransportWrapper, parse_connection_str, parse_query +from ._shared.response_handlers import process_storage_error + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + +if TYPE_CHECKING: + from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential, TokenCredential + from ._models import Metrics, ShareProtocolSettings + + +class ShareServiceClient(StorageAccountHostsMixin): + """A client to interact with the File Share Service at the account level. + + This client provides operations to retrieve and configure the account properties + as well as list, create and delete shares within the account. + For operations relating to a specific share, a client for that entity + can also be retrieved using the :func:`get_share_client` function. + + For more optional configuration, please click + `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #optional-configuration>`__. + + :param str account_url: + The URL to the file share storage account. Any other entities included + in the URL path (e.g. share or file) will be discarded. This URL can be optionally + authenticated with a SAS token. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a TokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials.TokenCredential or + str or dict[str, str] or None + :keyword token_intent: + Required when using `TokenCredential` for authentication and ignored for other forms of authentication. + Specifies the intent for all requests when using `TokenCredential` authentication. Possible values are: + + backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory + ACLs are bypassed and full permissions are granted. User must also have required RBAC permission. + + :paramtype token_intent: Literal['backup'] + :keyword bool allow_trailing_dot: If true, the trailing dot will not be trimmed from the target URI. + :keyword bool allow_source_trailing_dot: If true, the trailing dot will not be trimmed from the source URI. + :keyword str api_version: + The Storage API version to use for requests. Default value is the most recent service version that is + compatible with the current SDK. Setting to an older version may result in reduced feature compatibility. + + .. versionadded:: 12.1.0 + + :keyword str secondary_hostname: + The hostname of the secondary endpoint. + :keyword int max_range_size: The maximum range size used for a file upload. Defaults to 4*1024*1024. + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_authentication.py + :start-after: [START create_share_service_client] + :end-before: [END create_share_service_client] + :language: python + :dedent: 8 + :caption: Create the share service client with url and credential. + """ + def __init__( + self, account_url: str, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long + *, + token_intent: Optional[Literal['backup']] = None, + **kwargs: Any + ) -> None: + if hasattr(credential, 'get_token') and not token_intent: + raise ValueError("'token_intent' keyword is required when 'credential' is an TokenCredential.") + parsed_url = _parse_url(account_url=account_url) + _, sas_token = parse_query(parsed_url.query) + if not sas_token and not credential: + raise ValueError( + 'You need to provide either an account shared key or SAS token when creating a storage service.') + + self._query_str, credential = self._format_query_string(sas_token, credential) + super(ShareServiceClient, self).__init__( + parsed_url, service='file-share', credential=credential, **kwargs) + self.allow_trailing_dot = kwargs.pop('allow_trailing_dot', None) + self.allow_source_trailing_dot = kwargs.pop('allow_source_trailing_dot', None) + self.file_request_intent = token_intent + self._client = AzureFileStorage(url=self.url, base_url=self.url, pipeline=self._pipeline, + allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, + file_request_intent=self.file_request_intent) + self._client._config.version = get_api_version(kwargs) # type: ignore [assignment] + + def _format_url(self, hostname: str) -> str: + """Format the endpoint URL according to the current location mode hostname. + + :param str hostname: + The hostname of the current location mode. + :returns: A formatted endpoint URL including current location mode hostname. + :rtype: str + """ + return f"{self.scheme}://{hostname}/{self._query_str}" + + @classmethod + def from_connection_string( + cls, conn_str: str, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "TokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """Create ShareServiceClient from a Connection String. + + :param str conn_str: + A connection string to an Azure Storage account. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a TokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials.TokenCredential or + str or dict[str, str] or None + :returns: A File Share service client. + :rtype: ~azure.storage.fileshare.ShareServiceClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_authentication.py + :start-after: [START create_share_service_client_from_conn_string] + :end-before: [END create_share_service_client_from_conn_string] + :language: python + :dedent: 8 + :caption: Create the share service client with connection string. + """ + account_url, secondary, credential = parse_connection_str(conn_str, credential, 'file') + if 'secondary_hostname' not in kwargs: + kwargs['secondary_hostname'] = secondary + return cls(account_url, credential=credential, **kwargs) + + @distributed_trace + def get_service_properties(self, **kwargs: Any) -> Dict[str, Any]: + """Gets the properties of a storage account's File Share service, including + Azure Storage Analytics. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: A dictionary containing file service properties such as + analytics logging, hour/minute metrics, cors rules, etc. + :rtype: Dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_service.py + :start-after: [START get_service_properties] + :end-before: [END get_service_properties] + :language: python + :dedent: 8 + :caption: Get file share service properties. + """ + timeout = kwargs.pop('timeout', None) + try: + service_props = self._client.service.get_properties(timeout=timeout, **kwargs) + return service_properties_deserialize(service_props) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def set_service_properties( + self, hour_metrics: Optional["Metrics"] = None, + minute_metrics: Optional["Metrics"] = None, + cors: Optional[List[CorsRule]] = None, + protocol: Optional["ShareProtocolSettings"] = None, + **kwargs: Any + ) -> None: + """Sets the properties of a storage account's File Share service, including + Azure Storage Analytics. If an element (e.g. hour_metrics) is left as None, the + existing settings on the service for that functionality are preserved. + + :param hour_metrics: + The hour metrics settings provide a summary of request + statistics grouped by API in hourly aggregates for files. + :type hour_metrics: ~azure.storage.fileshare.Metrics + :param minute_metrics: + The minute metrics settings provide request statistics + for each minute for files. + :type minute_metrics: ~azure.storage.fileshare.Metrics + :param cors: + You can include up to five CorsRule elements in the + list. If an empty list is specified, all CORS rules will be deleted, + and CORS will be disabled for the service. + :type cors: list[~azure.storage.fileshare.CorsRule] + :param protocol: + Sets protocol settings + :type protocol: ~azure.storage.fileshare.ShareProtocolSettings + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_service.py + :start-after: [START set_service_properties] + :end-before: [END set_service_properties] + :language: python + :dedent: 8 + :caption: Sets file share service properties. + """ + timeout = kwargs.pop('timeout', None) + props = StorageServiceProperties( + hour_metrics=hour_metrics, + minute_metrics=minute_metrics, + cors=CorsRule._to_generated(cors), # pylint: disable=protected-access + protocol=protocol + ) + try: + self._client.service.set_properties(storage_service_properties=props, timeout=timeout, **kwargs) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def list_shares( + self, name_starts_with: Optional[str] = None, + include_metadata: Optional[bool] = False, + include_snapshots: Optional[bool] = False, + **kwargs: Any + ) -> ItemPaged[ShareProperties]: + """Returns auto-paging iterable of dict-like ShareProperties under the specified account. + The generator will lazily follow the continuation tokens returned by + the service and stop when all shares have been returned. + + :param str name_starts_with: + Filters the results to return only shares whose names + begin with the specified name_starts_with. + :param bool include_metadata: + Specifies that share metadata be returned in the response. + :param bool include_snapshots: + Specifies that share snapshot be returned in the response. + :keyword bool include_deleted: + Specifies that deleted shares be returned in the response. + This is only for share soft delete enabled account. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: An iterable (auto-paging) of ShareProperties. + :rtype: ~azure.core.paging.ItemPaged[~azure.storage.fileshare.ShareProperties] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_service.py + :start-after: [START fsc_list_shares] + :end-before: [END fsc_list_shares] + :language: python + :dedent: 12 + :caption: List shares in the file share service. + """ + timeout = kwargs.pop('timeout', None) + include = [] + include_deleted = kwargs.pop('include_deleted', None) + if include_deleted: + include.append("deleted") + if include_metadata: + include.append('metadata') + if include_snapshots: + include.append('snapshots') + + results_per_page = kwargs.pop('results_per_page', None) + command = functools.partial( + self._client.service.list_shares_segment, + include=include, + timeout=timeout, + **kwargs) + return ItemPaged( + command, prefix=name_starts_with, results_per_page=results_per_page, + page_iterator_class=SharePropertiesPaged) + + @distributed_trace + def create_share(self, share_name: str, **kwargs: Any) -> ShareClient: + """Creates a new share under the specified account. If the share + with the same name already exists, the operation fails. Returns a client with + which to interact with the newly created share. + + :param str share_name: The name of the share to create. + :keyword dict[str, str] metadata: + A dict with name_value pairs to associate with the + share as metadata. Example:{'Category':'test'} + :keyword int quota: + Quota in bytes. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword int provisioned_iops: The provisioned IOPS of the share, stored on the share object. + :keyword int provisioned_bandwidth_mibps: The provisioned throughput of the share, stored on the share object. + :return: A ShareClient for the newly created Share. + :rtype: ~azure.storage.fileshare.ShareClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_service.py + :start-after: [START fsc_create_shares] + :end-before: [END fsc_create_shares] + :language: python + :dedent: 8 + :caption: Create a share in the file share service. + """ + metadata = kwargs.pop('metadata', None) + quota = kwargs.pop('quota', None) + timeout = kwargs.pop('timeout', None) + provisioned_iops = kwargs.pop('provisioned_iops', None) + provisioned_bandwidth_mibps = kwargs.pop('provisioned_bandwidth_mibps', None) + share = self.get_share_client(share_name) + kwargs.setdefault('merge_span', True) + share.create_share( + metadata=metadata, + quota=quota, + timeout=timeout, + provisioned_iops=provisioned_iops, + provisioned_bandwidth_mibps=provisioned_bandwidth_mibps, + **kwargs + ) + return share + + @distributed_trace + def delete_share( + self, share_name: Union[ShareProperties, str], + delete_snapshots: Optional[bool] = False, + **kwargs: Any + ) -> None: + """Marks the specified share for deletion. The share is + later deleted during garbage collection. + + :param share_name: + The share to delete. This can either be the name of the share, + or an instance of ShareProperties. + :type share_name: str or ~azure.storage.fileshare.ShareProperties + :param bool delete_snapshots: + Indicates if snapshots are to be deleted. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_service.py + :start-after: [START fsc_delete_shares] + :end-before: [END fsc_delete_shares] + :language: python + :dedent: 12 + :caption: Delete a share in the file share service. + """ + timeout = kwargs.pop('timeout', None) + share = self.get_share_client(share_name) + kwargs.setdefault('merge_span', True) + share.delete_share( + delete_snapshots=delete_snapshots, timeout=timeout, **kwargs) + + @distributed_trace + def undelete_share(self, deleted_share_name: str, deleted_share_version: str, **kwargs: Any) -> ShareClient: + """Restores soft-deleted share. + + Operation will only be successful if used within the specified number of days + set in the delete retention policy. + + .. versionadded:: 12.2.0 + + This operation was introduced in API version '2019-12-12'. + + :param str deleted_share_name: + Specifies the name of the deleted share to restore. + :param str deleted_share_version: + Specifies the version of the deleted share to restore. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :return: A ShareClient for the undeleted Share. + :rtype: ~azure.storage.fileshare.ShareClient + """ + share = self.get_share_client(deleted_share_name) + + try: + share._client.share.restore(deleted_share_name=deleted_share_name, # pylint: disable=protected-access + deleted_share_version=deleted_share_version, + timeout=kwargs.pop('timeout', None), **kwargs) + return share + except HttpResponseError as error: + process_storage_error(error) + + def get_share_client( + self, share: Union[ShareProperties, str], + snapshot: Optional[Union[Dict[str, Any], str]] = None + ) -> ShareClient: + """Get a client to interact with the specified share. + The share need not already exist. + + :param share: + The share. This can either be the name of the share, + or an instance of ShareProperties. + :type share: str or ~azure.storage.fileshare.ShareProperties + :param str snapshot: + An optional share snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`create_snapshot`. + :returns: A ShareClient. + :rtype: ~azure.storage.fileshare.ShareClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_service.py + :start-after: [START get_share_client] + :end-before: [END get_share_client] + :language: python + :dedent: 8 + :caption: Gets the share client. + """ + if isinstance(share, ShareProperties): + share_name = share.name + else: + share_name = share + + _pipeline = Pipeline( + transport=TransportWrapper(self._pipeline._transport), # pylint: disable=protected-access + policies=self._pipeline._impl_policies # pylint: disable=protected-access + ) + return ShareClient( + self.url, share_name=share_name, snapshot=snapshot, credential=self.credential, + api_version=self.api_version, _hosts=self._hosts, + _configuration=self._config, _pipeline=_pipeline, _location_mode=self._location_mode, + allow_trailing_dot=self.allow_trailing_dot, allow_source_trailing_dot=self.allow_source_trailing_dot, + token_intent=self.file_request_intent) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_share_service_client_helpers.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_share_service_client_helpers.py new file mode 100644 index 00000000..9a6ebe8e --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_share_service_client_helpers.py @@ -0,0 +1,23 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from typing import TYPE_CHECKING +from urllib.parse import urlparse + +if TYPE_CHECKING: + from urllib.parse import ParseResult + + +def _parse_url(account_url: str) -> "ParseResult": + try: + if not account_url.lower().startswith("http"): + account_url = "https://" + account_url + except AttributeError as exc: + raise ValueError("Account URL must be a string.") from exc + parsed_url = urlparse(account_url.rstrip('/')) + if not parsed_url.netloc: + raise ValueError(f"Invalid URL: {account_url}") + return parsed_url diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/__init__.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/__init__.py new file mode 100644 index 00000000..a8b1a27d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/__init__.py @@ -0,0 +1,54 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import base64 +import hashlib +import hmac + +try: + from urllib.parse import quote, unquote +except ImportError: + from urllib2 import quote, unquote # type: ignore + + +def url_quote(url): + return quote(url) + + +def url_unquote(url): + return unquote(url) + + +def encode_base64(data): + if isinstance(data, str): + data = data.encode('utf-8') + encoded = base64.b64encode(data) + return encoded.decode('utf-8') + + +def decode_base64_to_bytes(data): + if isinstance(data, str): + data = data.encode('utf-8') + return base64.b64decode(data) + + +def decode_base64_to_text(data): + decoded_bytes = decode_base64_to_bytes(data) + return decoded_bytes.decode('utf-8') + + +def sign_string(key, string_to_sign, key_is_base64=True): + if key_is_base64: + key = decode_base64_to_bytes(key) + else: + if isinstance(key, str): + key = key.encode('utf-8') + if isinstance(string_to_sign, str): + string_to_sign = string_to_sign.encode('utf-8') + signed_hmac_sha256 = hmac.HMAC(key, string_to_sign, hashlib.sha256) + digest = signed_hmac_sha256.digest() + encoded_digest = encode_base64(digest) + return encoded_digest diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/authentication.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/authentication.py new file mode 100644 index 00000000..44c563d8 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/authentication.py @@ -0,0 +1,244 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import logging +import re +from typing import List, Tuple +from urllib.parse import unquote, urlparse +from functools import cmp_to_key + +try: + from yarl import URL +except ImportError: + pass + +try: + from azure.core.pipeline.transport import AioHttpTransport # pylint: disable=non-abstract-transport-import +except ImportError: + AioHttpTransport = None + +from azure.core.exceptions import ClientAuthenticationError +from azure.core.pipeline.policies import SansIOHTTPPolicy + +from . import sign_string + +logger = logging.getLogger(__name__) + +table_lv0 = [ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x71c, 0x0, 0x71f, 0x721, 0x723, 0x725, + 0x0, 0x0, 0x0, 0x72d, 0x803, 0x0, 0x0, 0x733, 0x0, 0xd03, 0xd1a, 0xd1c, 0xd1e, + 0xd20, 0xd22, 0xd24, 0xd26, 0xd28, 0xd2a, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0xe02, 0xe09, 0xe0a, 0xe1a, 0xe21, 0xe23, 0xe25, 0xe2c, 0xe32, 0xe35, 0xe36, 0xe48, 0xe51, + 0xe70, 0xe7c, 0xe7e, 0xe89, 0xe8a, 0xe91, 0xe99, 0xe9f, 0xea2, 0xea4, 0xea6, 0xea7, 0xea9, + 0x0, 0x0, 0x0, 0x743, 0x744, 0x748, 0xe02, 0xe09, 0xe0a, 0xe1a, 0xe21, 0xe23, 0xe25, + 0xe2c, 0xe32, 0xe35, 0xe36, 0xe48, 0xe51, 0xe70, 0xe7c, 0xe7e, 0xe89, 0xe8a, 0xe91, 0xe99, + 0xe9f, 0xea2, 0xea4, 0xea6, 0xea7, 0xea9, 0x0, 0x74c, 0x0, 0x750, 0x0, +] + +table_lv4 = [ + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8012, 0x0, 0x0, 0x0, 0x0, 0x0, 0x8212, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, +] + +def compare(lhs: str, rhs: str) -> int: # pylint:disable=too-many-return-statements + tables = [table_lv0, table_lv4] + curr_level, i, j, n = 0, 0, 0, len(tables) + lhs_len = len(lhs) + rhs_len = len(rhs) + while curr_level < n: + if curr_level == (n - 1) and i != j: + if i > j: + return -1 + if i < j: + return 1 + return 0 + + w1 = tables[curr_level][ord(lhs[i])] if i < lhs_len else 0x1 + w2 = tables[curr_level][ord(rhs[j])] if j < rhs_len else 0x1 + + if w1 == 0x1 and w2 == 0x1: + i = 0 + j = 0 + curr_level += 1 + elif w1 == w2: + i += 1 + j += 1 + elif w1 == 0: + i += 1 + elif w2 == 0: + j += 1 + else: + if w1 < w2: + return -1 + if w1 > w2: + return 1 + return 0 + return 0 + + +# wraps a given exception with the desired exception type +def _wrap_exception(ex, desired_type): + msg = "" + if ex.args: + msg = ex.args[0] + return desired_type(msg) + +# This method attempts to emulate the sorting done by the service +def _storage_header_sort(input_headers: List[Tuple[str, str]]) -> List[Tuple[str, str]]: + + # Build dict of tuples and list of keys + header_dict = {} + header_keys = [] + for k, v in input_headers: + header_dict[k] = v + header_keys.append(k) + + try: + header_keys = sorted(header_keys, key=cmp_to_key(compare)) + except ValueError as exc: + raise ValueError("Illegal character encountered when sorting headers.") from exc + + # Build list of sorted tuples + sorted_headers = [] + for key in header_keys: + sorted_headers.append((key, header_dict.pop(key))) + return sorted_headers + + +class AzureSigningError(ClientAuthenticationError): + """ + Represents a fatal error when attempting to sign a request. + In general, the cause of this exception is user error. For example, the given account key is not valid. + Please visit https://learn.microsoft.com/azure/storage/common/storage-create-storage-account for more info. + """ + + +class SharedKeyCredentialPolicy(SansIOHTTPPolicy): + + def __init__(self, account_name, account_key): + self.account_name = account_name + self.account_key = account_key + super(SharedKeyCredentialPolicy, self).__init__() + + @staticmethod + def _get_headers(request, headers_to_sign): + headers = dict((name.lower(), value) for name, value in request.http_request.headers.items() if value) + if 'content-length' in headers and headers['content-length'] == '0': + del headers['content-length'] + return '\n'.join(headers.get(x, '') for x in headers_to_sign) + '\n' + + @staticmethod + def _get_verb(request): + return request.http_request.method + '\n' + + def _get_canonicalized_resource(self, request): + uri_path = urlparse(request.http_request.url).path + try: + if isinstance(request.context.transport, AioHttpTransport) or \ + isinstance(getattr(request.context.transport, "_transport", None), AioHttpTransport) or \ + isinstance(getattr(getattr(request.context.transport, "_transport", None), "_transport", None), + AioHttpTransport): + uri_path = URL(uri_path) + return '/' + self.account_name + str(uri_path) + except TypeError: + pass + return '/' + self.account_name + uri_path + + @staticmethod + def _get_canonicalized_headers(request): + string_to_sign = '' + x_ms_headers = [] + for name, value in request.http_request.headers.items(): + if name.startswith('x-ms-'): + x_ms_headers.append((name.lower(), value)) + x_ms_headers = _storage_header_sort(x_ms_headers) + for name, value in x_ms_headers: + if value is not None: + string_to_sign += ''.join([name, ':', value, '\n']) + return string_to_sign + + @staticmethod + def _get_canonicalized_resource_query(request): + sorted_queries = list(request.http_request.query.items()) + sorted_queries.sort() + + string_to_sign = '' + for name, value in sorted_queries: + if value is not None: + string_to_sign += '\n' + name.lower() + ':' + unquote(value) + + return string_to_sign + + def _add_authorization_header(self, request, string_to_sign): + try: + signature = sign_string(self.account_key, string_to_sign) + auth_string = 'SharedKey ' + self.account_name + ':' + signature + request.http_request.headers['Authorization'] = auth_string + except Exception as ex: + # Wrap any error that occurred as signing error + # Doing so will clarify/locate the source of problem + raise _wrap_exception(ex, AzureSigningError) from ex + + def on_request(self, request): + string_to_sign = \ + self._get_verb(request) + \ + self._get_headers( + request, + [ + 'content-encoding', 'content-language', 'content-length', + 'content-md5', 'content-type', 'date', 'if-modified-since', + 'if-match', 'if-none-match', 'if-unmodified-since', 'byte_range' + ] + ) + \ + self._get_canonicalized_headers(request) + \ + self._get_canonicalized_resource(request) + \ + self._get_canonicalized_resource_query(request) + + self._add_authorization_header(request, string_to_sign) + # logger.debug("String_to_sign=%s", string_to_sign) + + +class StorageHttpChallenge(object): + def __init__(self, challenge): + """ Parses an HTTP WWW-Authentication Bearer challenge from the Storage service. """ + if not challenge: + raise ValueError("Challenge cannot be empty") + + self._parameters = {} + self.scheme, trimmed_challenge = challenge.strip().split(" ", 1) + + # name=value pairs either comma or space separated with values possibly being + # enclosed in quotes + for item in re.split('[, ]', trimmed_challenge): + comps = item.split("=") + if len(comps) == 2: + key = comps[0].strip(' "') + value = comps[1].strip(' "') + if key: + self._parameters[key] = value + + # Extract and verify required parameters + self.authorization_uri = self._parameters.get('authorization_uri') + if not self.authorization_uri: + raise ValueError("Authorization Uri not found") + + self.resource_id = self._parameters.get('resource_id') + if not self.resource_id: + raise ValueError("Resource id not found") + + uri_path = urlparse(self.authorization_uri).path.lstrip("/") + self.tenant_id = uri_path.split("/")[0] + + def get_value(self, key): + return self._parameters.get(key) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/base_client.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/base_client.py new file mode 100644 index 00000000..9dc8d2ec --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/base_client.py @@ -0,0 +1,458 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import logging +import uuid +from typing import ( + Any, + cast, + Dict, + Iterator, + Optional, + Tuple, + TYPE_CHECKING, + Union, +) +from urllib.parse import parse_qs, quote + +from azure.core.credentials import AzureSasCredential, AzureNamedKeyCredential, TokenCredential +from azure.core.exceptions import HttpResponseError +from azure.core.pipeline import Pipeline +from azure.core.pipeline.transport import HttpTransport, RequestsTransport # pylint: disable=non-abstract-transport-import, no-name-in-module +from azure.core.pipeline.policies import ( + AzureSasCredentialPolicy, + ContentDecodePolicy, + DistributedTracingPolicy, + HttpLoggingPolicy, + ProxyPolicy, + RedirectPolicy, + UserAgentPolicy, +) + +from .authentication import SharedKeyCredentialPolicy +from .constants import CONNECTION_TIMEOUT, DEFAULT_OAUTH_SCOPE, READ_TIMEOUT, SERVICE_HOST_BASE, STORAGE_OAUTH_SCOPE +from .models import LocationMode, StorageConfiguration +from .policies import ( + ExponentialRetry, + QueueMessagePolicy, + StorageBearerTokenCredentialPolicy, + StorageContentValidation, + StorageHeadersPolicy, + StorageHosts, + StorageLoggingPolicy, + StorageRequestHook, + StorageResponseHook, +) +from .request_handlers import serialize_batch_body, _get_batch_request_delimiter +from .response_handlers import PartialBatchErrorException, process_storage_error +from .shared_access_signature import QueryStringConstants +from .._version import VERSION +from .._shared_access_signature import _is_credential_sastoken + +if TYPE_CHECKING: + from azure.core.credentials_async import AsyncTokenCredential + from azure.core.pipeline.transport import HttpRequest, HttpResponse # pylint: disable=C4756 + +_LOGGER = logging.getLogger(__name__) +_SERVICE_PARAMS = { + "blob": {"primary": "BLOBENDPOINT", "secondary": "BLOBSECONDARYENDPOINT"}, + "queue": {"primary": "QUEUEENDPOINT", "secondary": "QUEUESECONDARYENDPOINT"}, + "file": {"primary": "FILEENDPOINT", "secondary": "FILESECONDARYENDPOINT"}, + "dfs": {"primary": "BLOBENDPOINT", "secondary": "BLOBENDPOINT"}, +} + + +class StorageAccountHostsMixin(object): + _client: Any + def __init__( + self, + parsed_url: Any, + service: str, + credential: Optional[Union[str, Dict[str, str], AzureNamedKeyCredential, AzureSasCredential, "AsyncTokenCredential", TokenCredential]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> None: + self._location_mode = kwargs.get("_location_mode", LocationMode.PRIMARY) + self._hosts = kwargs.get("_hosts") + self.scheme = parsed_url.scheme + self._is_localhost = False + + if service not in ["blob", "queue", "file-share", "dfs"]: + raise ValueError(f"Invalid service: {service}") + service_name = service.split('-')[0] + account = parsed_url.netloc.split(f".{service_name}.core.") + + self.account_name = account[0] if len(account) > 1 else None + if not self.account_name and parsed_url.netloc.startswith("localhost") \ + or parsed_url.netloc.startswith("127.0.0.1"): + self._is_localhost = True + self.account_name = parsed_url.path.strip("/") + + self.credential = _format_shared_key_credential(self.account_name, credential) + if self.scheme.lower() != "https" and hasattr(self.credential, "get_token"): + raise ValueError("Token credential is only supported with HTTPS.") + + secondary_hostname = None + if hasattr(self.credential, "account_name"): + self.account_name = self.credential.account_name + secondary_hostname = f"{self.credential.account_name}-secondary.{service_name}.{SERVICE_HOST_BASE}" + + if not self._hosts: + if len(account) > 1: + secondary_hostname = parsed_url.netloc.replace(account[0], account[0] + "-secondary") + if kwargs.get("secondary_hostname"): + secondary_hostname = kwargs["secondary_hostname"] + primary_hostname = (parsed_url.netloc + parsed_url.path).rstrip('/') + self._hosts = {LocationMode.PRIMARY: primary_hostname, LocationMode.SECONDARY: secondary_hostname} + + self._sdk_moniker = f"storage-{service}/{VERSION}" + self._config, self._pipeline = self._create_pipeline(self.credential, sdk_moniker=self._sdk_moniker, **kwargs) + + def __enter__(self): + self._client.__enter__() + return self + + def __exit__(self, *args): + self._client.__exit__(*args) + + def close(self): + """ This method is to close the sockets opened by the client. + It need not be used when using with a context manager. + """ + self._client.close() + + @property + def url(self): + """The full endpoint URL to this entity, including SAS token if used. + + This could be either the primary endpoint, + or the secondary endpoint depending on the current :func:`location_mode`. + :returns: The full endpoint URL to this entity, including SAS token if used. + :rtype: str + """ + return self._format_url(self._hosts[self._location_mode]) + + @property + def primary_endpoint(self): + """The full primary endpoint URL. + + :rtype: str + """ + return self._format_url(self._hosts[LocationMode.PRIMARY]) + + @property + def primary_hostname(self): + """The hostname of the primary endpoint. + + :rtype: str + """ + return self._hosts[LocationMode.PRIMARY] + + @property + def secondary_endpoint(self): + """The full secondary endpoint URL if configured. + + If not available a ValueError will be raised. To explicitly specify a secondary hostname, use the optional + `secondary_hostname` keyword argument on instantiation. + + :rtype: str + :raise ValueError: + """ + if not self._hosts[LocationMode.SECONDARY]: + raise ValueError("No secondary host configured.") + return self._format_url(self._hosts[LocationMode.SECONDARY]) + + @property + def secondary_hostname(self): + """The hostname of the secondary endpoint. + + If not available this will be None. To explicitly specify a secondary hostname, use the optional + `secondary_hostname` keyword argument on instantiation. + + :rtype: Optional[str] + """ + return self._hosts[LocationMode.SECONDARY] + + @property + def location_mode(self): + """The location mode that the client is currently using. + + By default this will be "primary". Options include "primary" and "secondary". + + :rtype: str + """ + + return self._location_mode + + @location_mode.setter + def location_mode(self, value): + if self._hosts.get(value): + self._location_mode = value + self._client._config.url = self.url # pylint: disable=protected-access + else: + raise ValueError(f"No host URL for location mode: {value}") + + @property + def api_version(self): + """The version of the Storage API used for requests. + + :rtype: str + """ + return self._client._config.version # pylint: disable=protected-access + + def _format_query_string( + self, sas_token: Optional[str], + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", TokenCredential]], # pylint: disable=line-too-long + snapshot: Optional[str] = None, + share_snapshot: Optional[str] = None + ) -> Tuple[str, Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", TokenCredential]]]: # pylint: disable=line-too-long + query_str = "?" + if snapshot: + query_str += f"snapshot={snapshot}&" + if share_snapshot: + query_str += f"sharesnapshot={share_snapshot}&" + if sas_token and isinstance(credential, AzureSasCredential): + raise ValueError( + "You cannot use AzureSasCredential when the resource URI also contains a Shared Access Signature.") + if _is_credential_sastoken(credential): + credential = cast(str, credential) + query_str += credential.lstrip("?") + credential = None + elif sas_token: + query_str += sas_token + return query_str.rstrip("?&"), credential + + def _create_pipeline( + self, credential: Optional[Union[str, Dict[str, str], AzureNamedKeyCredential, AzureSasCredential, TokenCredential]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Tuple[StorageConfiguration, Pipeline]: + self._credential_policy: Any = None + if hasattr(credential, "get_token"): + if kwargs.get('audience'): + audience = str(kwargs.pop('audience')).rstrip('/') + DEFAULT_OAUTH_SCOPE + else: + audience = STORAGE_OAUTH_SCOPE + self._credential_policy = StorageBearerTokenCredentialPolicy(cast(TokenCredential, credential), audience) + elif isinstance(credential, SharedKeyCredentialPolicy): + self._credential_policy = credential + elif isinstance(credential, AzureSasCredential): + self._credential_policy = AzureSasCredentialPolicy(credential) + elif credential is not None: + raise TypeError(f"Unsupported credential: {type(credential)}") + + config = kwargs.get("_configuration") or create_configuration(**kwargs) + if kwargs.get("_pipeline"): + return config, kwargs["_pipeline"] + transport = kwargs.get("transport") + kwargs.setdefault("connection_timeout", CONNECTION_TIMEOUT) + kwargs.setdefault("read_timeout", READ_TIMEOUT) + if not transport: + transport = RequestsTransport(**kwargs) + policies = [ + QueueMessagePolicy(), + config.proxy_policy, + config.user_agent_policy, + StorageContentValidation(), + ContentDecodePolicy(response_encoding="utf-8"), + RedirectPolicy(**kwargs), + StorageHosts(hosts=self._hosts, **kwargs), + config.retry_policy, + config.headers_policy, + StorageRequestHook(**kwargs), + self._credential_policy, + config.logging_policy, + StorageResponseHook(**kwargs), + DistributedTracingPolicy(**kwargs), + HttpLoggingPolicy(**kwargs) + ] + if kwargs.get("_additional_pipeline_policies"): + policies = policies + kwargs.get("_additional_pipeline_policies") # type: ignore + config.transport = transport # type: ignore + return config, Pipeline(transport, policies=policies) + + def _batch_send( + self, + *reqs: "HttpRequest", + **kwargs: Any + ) -> Iterator["HttpResponse"]: + """Given a series of request, do a Storage batch call. + + :param HttpRequest reqs: A collection of HttpRequest objects. + :returns: An iterator of HttpResponse objects. + :rtype: Iterator[HttpResponse] + """ + # Pop it here, so requests doesn't feel bad about additional kwarg + raise_on_any_failure = kwargs.pop("raise_on_any_failure", True) + batch_id = str(uuid.uuid1()) + + request = self._client._client.post( # pylint: disable=protected-access + url=( + f'{self.scheme}://{self.primary_hostname}/' + f"{kwargs.pop('path', '')}?{kwargs.pop('restype', '')}" + f"comp=batch{kwargs.pop('sas', '')}{kwargs.pop('timeout', '')}" + ), + headers={ + 'x-ms-version': self.api_version, + "Content-Type": "multipart/mixed; boundary=" + _get_batch_request_delimiter(batch_id, False, False) + } + ) + + policies = [StorageHeadersPolicy()] + if self._credential_policy: + policies.append(self._credential_policy) + + request.set_multipart_mixed( + *reqs, + policies=policies, + enforce_https=False + ) + + Pipeline._prepare_multipart_mixed_request(request) # pylint: disable=protected-access + body = serialize_batch_body(request.multipart_mixed_info[0], batch_id) + request.set_bytes_body(body) + + temp = request.multipart_mixed_info + request.multipart_mixed_info = None + pipeline_response = self._pipeline.run( + request, **kwargs + ) + response = pipeline_response.http_response + request.multipart_mixed_info = temp + + try: + if response.status_code not in [202]: + raise HttpResponseError(response=response) + parts = response.parts() + if raise_on_any_failure: + parts = list(response.parts()) + if any(p for p in parts if not 200 <= p.status_code < 300): + error = PartialBatchErrorException( + message="There is a partial failure in the batch operation.", + response=response, parts=parts + ) + raise error + return iter(parts) + return parts # type: ignore [no-any-return] + except HttpResponseError as error: + process_storage_error(error) + + +class TransportWrapper(HttpTransport): + """Wrapper class that ensures that an inner client created + by a `get_client` method does not close the outer transport for the parent + when used in a context manager. + """ + def __init__(self, transport): + self._transport = transport + + def send(self, request, **kwargs): + return self._transport.send(request, **kwargs) + + def open(self): + pass + + def close(self): + pass + + def __enter__(self): + pass + + def __exit__(self, *args): + pass + + +def _format_shared_key_credential( + account_name: Optional[str], + credential: Optional[Union[str, Dict[str, str], AzureNamedKeyCredential, AzureSasCredential, "AsyncTokenCredential", TokenCredential]] = None # pylint: disable=line-too-long +) -> Any: + if isinstance(credential, str): + if not account_name: + raise ValueError("Unable to determine account name for shared key credential.") + credential = {"account_name": account_name, "account_key": credential} + if isinstance(credential, dict): + if "account_name" not in credential: + raise ValueError("Shared key credential missing 'account_name") + if "account_key" not in credential: + raise ValueError("Shared key credential missing 'account_key") + return SharedKeyCredentialPolicy(**credential) + if isinstance(credential, AzureNamedKeyCredential): + return SharedKeyCredentialPolicy(credential.named_key.name, credential.named_key.key) + return credential + + +def parse_connection_str( + conn_str: str, + credential: Optional[Union[str, Dict[str, str], AzureNamedKeyCredential, AzureSasCredential, TokenCredential]], + service: str +) -> Tuple[str, Optional[str], Optional[Union[str, Dict[str, str], AzureNamedKeyCredential, AzureSasCredential, TokenCredential]]]: # pylint: disable=line-too-long + conn_str = conn_str.rstrip(";") + conn_settings_list = [s.split("=", 1) for s in conn_str.split(";")] + if any(len(tup) != 2 for tup in conn_settings_list): + raise ValueError("Connection string is either blank or malformed.") + conn_settings = dict((key.upper(), val) for key, val in conn_settings_list) + endpoints = _SERVICE_PARAMS[service] + primary = None + secondary = None + if not credential: + try: + credential = {"account_name": conn_settings["ACCOUNTNAME"], "account_key": conn_settings["ACCOUNTKEY"]} + except KeyError: + credential = conn_settings.get("SHAREDACCESSSIGNATURE") + if endpoints["primary"] in conn_settings: + primary = conn_settings[endpoints["primary"]] + if endpoints["secondary"] in conn_settings: + secondary = conn_settings[endpoints["secondary"]] + else: + if endpoints["secondary"] in conn_settings: + raise ValueError("Connection string specifies only secondary endpoint.") + try: + primary =( + f"{conn_settings['DEFAULTENDPOINTSPROTOCOL']}://" + f"{conn_settings['ACCOUNTNAME']}.{service}.{conn_settings['ENDPOINTSUFFIX']}" + ) + secondary = ( + f"{conn_settings['ACCOUNTNAME']}-secondary." + f"{service}.{conn_settings['ENDPOINTSUFFIX']}" + ) + except KeyError: + pass + + if not primary: + try: + primary = ( + f"https://{conn_settings['ACCOUNTNAME']}." + f"{service}.{conn_settings.get('ENDPOINTSUFFIX', SERVICE_HOST_BASE)}" + ) + except KeyError as exc: + raise ValueError("Connection string missing required connection details.") from exc + if service == "dfs": + primary = primary.replace(".blob.", ".dfs.") + if secondary: + secondary = secondary.replace(".blob.", ".dfs.") + return primary, secondary, credential + + +def create_configuration(**kwargs: Any) -> StorageConfiguration: + # Backwards compatibility if someone is not passing sdk_moniker + if not kwargs.get("sdk_moniker"): + kwargs["sdk_moniker"] = f"storage-{kwargs.pop('storage_sdk')}/{VERSION}" + config = StorageConfiguration(**kwargs) + config.headers_policy = StorageHeadersPolicy(**kwargs) + config.user_agent_policy = UserAgentPolicy(**kwargs) + config.retry_policy = kwargs.get("retry_policy") or ExponentialRetry(**kwargs) + config.logging_policy = StorageLoggingPolicy(**kwargs) + config.proxy_policy = ProxyPolicy(**kwargs) + return config + + +def parse_query(query_str: str) -> Tuple[Optional[str], Optional[str]]: + sas_values = QueryStringConstants.to_list() + parsed_query = {k: v[0] for k, v in parse_qs(query_str).items()} + sas_params = [f"{k}={quote(v, safe='')}" for k, v in parsed_query.items() if k in sas_values] + sas_token = None + if sas_params: + sas_token = "&".join(sas_params) + + snapshot = parsed_query.get("snapshot") or parsed_query.get("sharesnapshot") + return snapshot, sas_token diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/base_client_async.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/base_client_async.py new file mode 100644 index 00000000..6186b29d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/base_client_async.py @@ -0,0 +1,280 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# mypy: disable-error-code="attr-defined" + +import logging +from typing import Any, cast, Dict, Optional, Tuple, TYPE_CHECKING, Union + +from azure.core.async_paging import AsyncList +from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential +from azure.core.credentials_async import AsyncTokenCredential +from azure.core.exceptions import HttpResponseError +from azure.core.pipeline import AsyncPipeline +from azure.core.pipeline.policies import ( + AsyncRedirectPolicy, + AzureSasCredentialPolicy, + ContentDecodePolicy, + DistributedTracingPolicy, + HttpLoggingPolicy, +) +from azure.core.pipeline.transport import AsyncHttpTransport + +from .authentication import SharedKeyCredentialPolicy +from .base_client import create_configuration +from .constants import CONNECTION_TIMEOUT, DEFAULT_OAUTH_SCOPE, READ_TIMEOUT, SERVICE_HOST_BASE, STORAGE_OAUTH_SCOPE +from .models import StorageConfiguration +from .policies import ( + QueueMessagePolicy, + StorageContentValidation, + StorageHeadersPolicy, + StorageHosts, + StorageRequestHook, +) +from .policies_async import AsyncStorageBearerTokenCredentialPolicy, AsyncStorageResponseHook +from .response_handlers import PartialBatchErrorException, process_storage_error +from .._shared_access_signature import _is_credential_sastoken + +if TYPE_CHECKING: + from azure.core.pipeline.transport import HttpRequest, HttpResponse # pylint: disable=C4756 +_LOGGER = logging.getLogger(__name__) + +_SERVICE_PARAMS = { + "blob": {"primary": "BLOBENDPOINT", "secondary": "BLOBSECONDARYENDPOINT"}, + "queue": {"primary": "QUEUEENDPOINT", "secondary": "QUEUESECONDARYENDPOINT"}, + "file": {"primary": "FILEENDPOINT", "secondary": "FILESECONDARYENDPOINT"}, + "dfs": {"primary": "BLOBENDPOINT", "secondary": "BLOBENDPOINT"}, +} + + +class AsyncStorageAccountHostsMixin(object): + + def __enter__(self): + raise TypeError("Async client only supports 'async with'.") + + def __exit__(self, *args): + pass + + async def __aenter__(self): + await self._client.__aenter__() + return self + + async def __aexit__(self, *args): + await self._client.__aexit__(*args) + + async def close(self): + """ This method is to close the sockets opened by the client. + It need not be used when using with a context manager. + """ + await self._client.close() + + def _format_query_string( + self, sas_token: Optional[str], + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", AsyncTokenCredential]], # pylint: disable=line-too-long + snapshot: Optional[str] = None, + share_snapshot: Optional[str] = None + ) -> Tuple[str, Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", AsyncTokenCredential]]]: # pylint: disable=line-too-long + query_str = "?" + if snapshot: + query_str += f"snapshot={snapshot}&" + if share_snapshot: + query_str += f"sharesnapshot={share_snapshot}&" + if sas_token and isinstance(credential, AzureSasCredential): + raise ValueError( + "You cannot use AzureSasCredential when the resource URI also contains a Shared Access Signature.") + if _is_credential_sastoken(credential): + query_str += credential.lstrip("?") # type: ignore [union-attr] + credential = None + elif sas_token: + query_str += sas_token + return query_str.rstrip("?&"), credential + + def _create_pipeline( + self, credential: Optional[Union[str, Dict[str, str], AzureNamedKeyCredential, AzureSasCredential, AsyncTokenCredential]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Tuple[StorageConfiguration, AsyncPipeline]: + self._credential_policy: Optional[ + Union[AsyncStorageBearerTokenCredentialPolicy, + SharedKeyCredentialPolicy, + AzureSasCredentialPolicy]] = None + if hasattr(credential, 'get_token'): + if kwargs.get('audience'): + audience = str(kwargs.pop('audience')).rstrip('/') + DEFAULT_OAUTH_SCOPE + else: + audience = STORAGE_OAUTH_SCOPE + self._credential_policy = AsyncStorageBearerTokenCredentialPolicy( + cast(AsyncTokenCredential, credential), audience) + elif isinstance(credential, SharedKeyCredentialPolicy): + self._credential_policy = credential + elif isinstance(credential, AzureSasCredential): + self._credential_policy = AzureSasCredentialPolicy(credential) + elif credential is not None: + raise TypeError(f"Unsupported credential: {type(credential)}") + config = kwargs.get('_configuration') or create_configuration(**kwargs) + if kwargs.get('_pipeline'): + return config, kwargs['_pipeline'] + transport = kwargs.get('transport') + kwargs.setdefault("connection_timeout", CONNECTION_TIMEOUT) + kwargs.setdefault("read_timeout", READ_TIMEOUT) + if not transport: + try: + from azure.core.pipeline.transport import AioHttpTransport # pylint: disable=non-abstract-transport-import + except ImportError as exc: + raise ImportError("Unable to create async transport. Please check aiohttp is installed.") from exc + transport = AioHttpTransport(**kwargs) + hosts = self._hosts + policies = [ + QueueMessagePolicy(), + config.proxy_policy, + config.user_agent_policy, + StorageContentValidation(), + ContentDecodePolicy(response_encoding="utf-8"), + AsyncRedirectPolicy(**kwargs), + StorageHosts(hosts=hosts, **kwargs), + config.retry_policy, + config.headers_policy, + StorageRequestHook(**kwargs), + self._credential_policy, + config.logging_policy, + AsyncStorageResponseHook(**kwargs), + DistributedTracingPolicy(**kwargs), + HttpLoggingPolicy(**kwargs), + ] + if kwargs.get("_additional_pipeline_policies"): + policies = policies + kwargs.get("_additional_pipeline_policies") #type: ignore + config.transport = transport #type: ignore + return config, AsyncPipeline(transport, policies=policies) #type: ignore + + async def _batch_send( + self, + *reqs: "HttpRequest", + **kwargs: Any + ) -> AsyncList["HttpResponse"]: + """Given a series of request, do a Storage batch call. + + :param HttpRequest reqs: A collection of HttpRequest objects. + :returns: An AsyncList of HttpResponse objects. + :rtype: AsyncList[HttpResponse] + """ + # Pop it here, so requests doesn't feel bad about additional kwarg + raise_on_any_failure = kwargs.pop("raise_on_any_failure", True) + request = self._client._client.post( # pylint: disable=protected-access + url=( + f'{self.scheme}://{self.primary_hostname}/' + f"{kwargs.pop('path', '')}?{kwargs.pop('restype', '')}" + f"comp=batch{kwargs.pop('sas', '')}{kwargs.pop('timeout', '')}" + ), + headers={ + 'x-ms-version': self.api_version + } + ) + + policies = [StorageHeadersPolicy()] + if self._credential_policy: + policies.append(self._credential_policy) # type: ignore + + request.set_multipart_mixed( + *reqs, + policies=policies, + enforce_https=False + ) + + pipeline_response = await self._pipeline.run( + request, **kwargs + ) + response = pipeline_response.http_response + + try: + if response.status_code not in [202]: + raise HttpResponseError(response=response) + parts = response.parts() # Return an AsyncIterator + if raise_on_any_failure: + parts_list = [] + async for part in parts: + parts_list.append(part) + if any(p for p in parts_list if not 200 <= p.status_code < 300): + error = PartialBatchErrorException( + message="There is a partial failure in the batch operation.", + response=response, parts=parts_list + ) + raise error + return AsyncList(parts_list) + return parts # type: ignore [no-any-return] + except HttpResponseError as error: + process_storage_error(error) + +def parse_connection_str( + conn_str: str, + credential: Optional[Union[str, Dict[str, str], AzureNamedKeyCredential, AzureSasCredential, AsyncTokenCredential]], + service: str +) -> Tuple[str, Optional[str], Optional[Union[str, Dict[str, str], AzureNamedKeyCredential, AzureSasCredential, AsyncTokenCredential]]]: # pylint: disable=line-too-long + conn_str = conn_str.rstrip(";") + conn_settings_list = [s.split("=", 1) for s in conn_str.split(";")] + if any(len(tup) != 2 for tup in conn_settings_list): + raise ValueError("Connection string is either blank or malformed.") + conn_settings = dict((key.upper(), val) for key, val in conn_settings_list) + endpoints = _SERVICE_PARAMS[service] + primary = None + secondary = None + if not credential: + try: + credential = {"account_name": conn_settings["ACCOUNTNAME"], "account_key": conn_settings["ACCOUNTKEY"]} + except KeyError: + credential = conn_settings.get("SHAREDACCESSSIGNATURE") + if endpoints["primary"] in conn_settings: + primary = conn_settings[endpoints["primary"]] + if endpoints["secondary"] in conn_settings: + secondary = conn_settings[endpoints["secondary"]] + else: + if endpoints["secondary"] in conn_settings: + raise ValueError("Connection string specifies only secondary endpoint.") + try: + primary =( + f"{conn_settings['DEFAULTENDPOINTSPROTOCOL']}://" + f"{conn_settings['ACCOUNTNAME']}.{service}.{conn_settings['ENDPOINTSUFFIX']}" + ) + secondary = ( + f"{conn_settings['ACCOUNTNAME']}-secondary." + f"{service}.{conn_settings['ENDPOINTSUFFIX']}" + ) + except KeyError: + pass + + if not primary: + try: + primary = ( + f"https://{conn_settings['ACCOUNTNAME']}." + f"{service}.{conn_settings.get('ENDPOINTSUFFIX', SERVICE_HOST_BASE)}" + ) + except KeyError as exc: + raise ValueError("Connection string missing required connection details.") from exc + if service == "dfs": + primary = primary.replace(".blob.", ".dfs.") + if secondary: + secondary = secondary.replace(".blob.", ".dfs.") + return primary, secondary, credential + +class AsyncTransportWrapper(AsyncHttpTransport): + """Wrapper class that ensures that an inner client created + by a `get_client` method does not close the outer transport for the parent + when used in a context manager. + """ + def __init__(self, async_transport): + self._transport = async_transport + + async def send(self, request, **kwargs): + return await self._transport.send(request, **kwargs) + + async def open(self): + pass + + async def close(self): + pass + + async def __aenter__(self): + pass + + async def __aexit__(self, *args): + pass diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/constants.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/constants.py new file mode 100644 index 00000000..0b4b029a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/constants.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from .._serialize import _SUPPORTED_API_VERSIONS + + +X_MS_VERSION = _SUPPORTED_API_VERSIONS[-1] + +# Default socket timeouts, in seconds +CONNECTION_TIMEOUT = 20 +READ_TIMEOUT = 60 + +DEFAULT_OAUTH_SCOPE = "/.default" +STORAGE_OAUTH_SCOPE = "https://storage.azure.com/.default" + +SERVICE_HOST_BASE = 'core.windows.net' diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/models.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/models.py new file mode 100644 index 00000000..403e6b8b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/models.py @@ -0,0 +1,585 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=too-many-instance-attributes +from enum import Enum +from typing import Optional + +from azure.core import CaseInsensitiveEnumMeta +from azure.core.configuration import Configuration +from azure.core.pipeline.policies import UserAgentPolicy + + +def get_enum_value(value): + if value is None or value in ["None", ""]: + return None + try: + return value.value + except AttributeError: + return value + + +class StorageErrorCode(str, Enum, metaclass=CaseInsensitiveEnumMeta): + + # Generic storage values + ACCOUNT_ALREADY_EXISTS = "AccountAlreadyExists" + ACCOUNT_BEING_CREATED = "AccountBeingCreated" + ACCOUNT_IS_DISABLED = "AccountIsDisabled" + AUTHENTICATION_FAILED = "AuthenticationFailed" + AUTHORIZATION_FAILURE = "AuthorizationFailure" + NO_AUTHENTICATION_INFORMATION = "NoAuthenticationInformation" + CONDITION_HEADERS_NOT_SUPPORTED = "ConditionHeadersNotSupported" + CONDITION_NOT_MET = "ConditionNotMet" + EMPTY_METADATA_KEY = "EmptyMetadataKey" + INSUFFICIENT_ACCOUNT_PERMISSIONS = "InsufficientAccountPermissions" + INTERNAL_ERROR = "InternalError" + INVALID_AUTHENTICATION_INFO = "InvalidAuthenticationInfo" + INVALID_HEADER_VALUE = "InvalidHeaderValue" + INVALID_HTTP_VERB = "InvalidHttpVerb" + INVALID_INPUT = "InvalidInput" + INVALID_MD5 = "InvalidMd5" + INVALID_METADATA = "InvalidMetadata" + INVALID_QUERY_PARAMETER_VALUE = "InvalidQueryParameterValue" + INVALID_RANGE = "InvalidRange" + INVALID_RESOURCE_NAME = "InvalidResourceName" + INVALID_URI = "InvalidUri" + INVALID_XML_DOCUMENT = "InvalidXmlDocument" + INVALID_XML_NODE_VALUE = "InvalidXmlNodeValue" + MD5_MISMATCH = "Md5Mismatch" + METADATA_TOO_LARGE = "MetadataTooLarge" + MISSING_CONTENT_LENGTH_HEADER = "MissingContentLengthHeader" + MISSING_REQUIRED_QUERY_PARAMETER = "MissingRequiredQueryParameter" + MISSING_REQUIRED_HEADER = "MissingRequiredHeader" + MISSING_REQUIRED_XML_NODE = "MissingRequiredXmlNode" + MULTIPLE_CONDITION_HEADERS_NOT_SUPPORTED = "MultipleConditionHeadersNotSupported" + OPERATION_TIMED_OUT = "OperationTimedOut" + OUT_OF_RANGE_INPUT = "OutOfRangeInput" + OUT_OF_RANGE_QUERY_PARAMETER_VALUE = "OutOfRangeQueryParameterValue" + REQUEST_BODY_TOO_LARGE = "RequestBodyTooLarge" + RESOURCE_TYPE_MISMATCH = "ResourceTypeMismatch" + REQUEST_URL_FAILED_TO_PARSE = "RequestUrlFailedToParse" + RESOURCE_ALREADY_EXISTS = "ResourceAlreadyExists" + RESOURCE_NOT_FOUND = "ResourceNotFound" + SERVER_BUSY = "ServerBusy" + UNSUPPORTED_HEADER = "UnsupportedHeader" + UNSUPPORTED_XML_NODE = "UnsupportedXmlNode" + UNSUPPORTED_QUERY_PARAMETER = "UnsupportedQueryParameter" + UNSUPPORTED_HTTP_VERB = "UnsupportedHttpVerb" + + # Blob values + APPEND_POSITION_CONDITION_NOT_MET = "AppendPositionConditionNotMet" + BLOB_ACCESS_TIER_NOT_SUPPORTED_FOR_ACCOUNT_TYPE = "BlobAccessTierNotSupportedForAccountType" + BLOB_ALREADY_EXISTS = "BlobAlreadyExists" + BLOB_NOT_FOUND = "BlobNotFound" + BLOB_OVERWRITTEN = "BlobOverwritten" + BLOB_TIER_INADEQUATE_FOR_CONTENT_LENGTH = "BlobTierInadequateForContentLength" + BLOCK_COUNT_EXCEEDS_LIMIT = "BlockCountExceedsLimit" + BLOCK_LIST_TOO_LONG = "BlockListTooLong" + CANNOT_CHANGE_TO_LOWER_TIER = "CannotChangeToLowerTier" + CANNOT_VERIFY_COPY_SOURCE = "CannotVerifyCopySource" + CONTAINER_ALREADY_EXISTS = "ContainerAlreadyExists" + CONTAINER_BEING_DELETED = "ContainerBeingDeleted" + CONTAINER_DISABLED = "ContainerDisabled" + CONTAINER_NOT_FOUND = "ContainerNotFound" + CONTENT_LENGTH_LARGER_THAN_TIER_LIMIT = "ContentLengthLargerThanTierLimit" + COPY_ACROSS_ACCOUNTS_NOT_SUPPORTED = "CopyAcrossAccountsNotSupported" + COPY_ID_MISMATCH = "CopyIdMismatch" + FEATURE_VERSION_MISMATCH = "FeatureVersionMismatch" + INCREMENTAL_COPY_BLOB_MISMATCH = "IncrementalCopyBlobMismatch" + INCREMENTAL_COPY_OF_EARLIER_VERSION_SNAPSHOT_NOT_ALLOWED = "IncrementalCopyOfEarlierVersionSnapshotNotAllowed" + #: Deprecated: Please use INCREMENTAL_COPY_OF_EARLIER_VERSION_SNAPSHOT_NOT_ALLOWED instead. + INCREMENTAL_COPY_OF_ERALIER_VERSION_SNAPSHOT_NOT_ALLOWED = "IncrementalCopyOfEarlierVersionSnapshotNotAllowed" + INCREMENTAL_COPY_SOURCE_MUST_BE_SNAPSHOT = "IncrementalCopySourceMustBeSnapshot" + INFINITE_LEASE_DURATION_REQUIRED = "InfiniteLeaseDurationRequired" + INVALID_BLOB_OR_BLOCK = "InvalidBlobOrBlock" + INVALID_BLOB_TIER = "InvalidBlobTier" + INVALID_BLOB_TYPE = "InvalidBlobType" + INVALID_BLOCK_ID = "InvalidBlockId" + INVALID_BLOCK_LIST = "InvalidBlockList" + INVALID_OPERATION = "InvalidOperation" + INVALID_PAGE_RANGE = "InvalidPageRange" + INVALID_SOURCE_BLOB_TYPE = "InvalidSourceBlobType" + INVALID_SOURCE_BLOB_URL = "InvalidSourceBlobUrl" + INVALID_VERSION_FOR_PAGE_BLOB_OPERATION = "InvalidVersionForPageBlobOperation" + LEASE_ALREADY_PRESENT = "LeaseAlreadyPresent" + LEASE_ALREADY_BROKEN = "LeaseAlreadyBroken" + LEASE_ID_MISMATCH_WITH_BLOB_OPERATION = "LeaseIdMismatchWithBlobOperation" + LEASE_ID_MISMATCH_WITH_CONTAINER_OPERATION = "LeaseIdMismatchWithContainerOperation" + LEASE_ID_MISMATCH_WITH_LEASE_OPERATION = "LeaseIdMismatchWithLeaseOperation" + LEASE_ID_MISSING = "LeaseIdMissing" + LEASE_IS_BREAKING_AND_CANNOT_BE_ACQUIRED = "LeaseIsBreakingAndCannotBeAcquired" + LEASE_IS_BREAKING_AND_CANNOT_BE_CHANGED = "LeaseIsBreakingAndCannotBeChanged" + LEASE_IS_BROKEN_AND_CANNOT_BE_RENEWED = "LeaseIsBrokenAndCannotBeRenewed" + LEASE_LOST = "LeaseLost" + LEASE_NOT_PRESENT_WITH_BLOB_OPERATION = "LeaseNotPresentWithBlobOperation" + LEASE_NOT_PRESENT_WITH_CONTAINER_OPERATION = "LeaseNotPresentWithContainerOperation" + LEASE_NOT_PRESENT_WITH_LEASE_OPERATION = "LeaseNotPresentWithLeaseOperation" + MAX_BLOB_SIZE_CONDITION_NOT_MET = "MaxBlobSizeConditionNotMet" + NO_PENDING_COPY_OPERATION = "NoPendingCopyOperation" + OPERATION_NOT_ALLOWED_ON_INCREMENTAL_COPY_BLOB = "OperationNotAllowedOnIncrementalCopyBlob" + PENDING_COPY_OPERATION = "PendingCopyOperation" + PREVIOUS_SNAPSHOT_CANNOT_BE_NEWER = "PreviousSnapshotCannotBeNewer" + PREVIOUS_SNAPSHOT_NOT_FOUND = "PreviousSnapshotNotFound" + PREVIOUS_SNAPSHOT_OPERATION_NOT_SUPPORTED = "PreviousSnapshotOperationNotSupported" + SEQUENCE_NUMBER_CONDITION_NOT_MET = "SequenceNumberConditionNotMet" + SEQUENCE_NUMBER_INCREMENT_TOO_LARGE = "SequenceNumberIncrementTooLarge" + SNAPSHOT_COUNT_EXCEEDED = "SnapshotCountExceeded" + SNAPSHOT_OPERATION_RATE_EXCEEDED = "SnapshotOperationRateExceeded" + #: Deprecated: Please use SNAPSHOT_OPERATION_RATE_EXCEEDED instead. + SNAPHOT_OPERATION_RATE_EXCEEDED = "SnapshotOperationRateExceeded" + SNAPSHOTS_PRESENT = "SnapshotsPresent" + SOURCE_CONDITION_NOT_MET = "SourceConditionNotMet" + SYSTEM_IN_USE = "SystemInUse" + TARGET_CONDITION_NOT_MET = "TargetConditionNotMet" + UNAUTHORIZED_BLOB_OVERWRITE = "UnauthorizedBlobOverwrite" + BLOB_BEING_REHYDRATED = "BlobBeingRehydrated" + BLOB_ARCHIVED = "BlobArchived" + BLOB_NOT_ARCHIVED = "BlobNotArchived" + + # Queue values + INVALID_MARKER = "InvalidMarker" + MESSAGE_NOT_FOUND = "MessageNotFound" + MESSAGE_TOO_LARGE = "MessageTooLarge" + POP_RECEIPT_MISMATCH = "PopReceiptMismatch" + QUEUE_ALREADY_EXISTS = "QueueAlreadyExists" + QUEUE_BEING_DELETED = "QueueBeingDeleted" + QUEUE_DISABLED = "QueueDisabled" + QUEUE_NOT_EMPTY = "QueueNotEmpty" + QUEUE_NOT_FOUND = "QueueNotFound" + + # File values + CANNOT_DELETE_FILE_OR_DIRECTORY = "CannotDeleteFileOrDirectory" + CLIENT_CACHE_FLUSH_DELAY = "ClientCacheFlushDelay" + DELETE_PENDING = "DeletePending" + DIRECTORY_NOT_EMPTY = "DirectoryNotEmpty" + FILE_LOCK_CONFLICT = "FileLockConflict" + FILE_SHARE_PROVISIONED_BANDWIDTH_DOWNGRADE_NOT_ALLOWED = "FileShareProvisionedBandwidthDowngradeNotAllowed" + FILE_SHARE_PROVISIONED_IOPS_DOWNGRADE_NOT_ALLOWED = "FileShareProvisionedIopsDowngradeNotAllowed" + INVALID_FILE_OR_DIRECTORY_PATH_NAME = "InvalidFileOrDirectoryPathName" + PARENT_NOT_FOUND = "ParentNotFound" + READ_ONLY_ATTRIBUTE = "ReadOnlyAttribute" + SHARE_ALREADY_EXISTS = "ShareAlreadyExists" + SHARE_BEING_DELETED = "ShareBeingDeleted" + SHARE_DISABLED = "ShareDisabled" + SHARE_NOT_FOUND = "ShareNotFound" + SHARING_VIOLATION = "SharingViolation" + SHARE_SNAPSHOT_IN_PROGRESS = "ShareSnapshotInProgress" + SHARE_SNAPSHOT_COUNT_EXCEEDED = "ShareSnapshotCountExceeded" + SHARE_SNAPSHOT_OPERATION_NOT_SUPPORTED = "ShareSnapshotOperationNotSupported" + SHARE_HAS_SNAPSHOTS = "ShareHasSnapshots" + CONTAINER_QUOTA_DOWNGRADE_NOT_ALLOWED = "ContainerQuotaDowngradeNotAllowed" + + # DataLake values + CONTENT_LENGTH_MUST_BE_ZERO = 'ContentLengthMustBeZero' + PATH_ALREADY_EXISTS = 'PathAlreadyExists' + INVALID_FLUSH_POSITION = 'InvalidFlushPosition' + INVALID_PROPERTY_NAME = 'InvalidPropertyName' + INVALID_SOURCE_URI = 'InvalidSourceUri' + UNSUPPORTED_REST_VERSION = 'UnsupportedRestVersion' + FILE_SYSTEM_NOT_FOUND = 'FilesystemNotFound' + PATH_NOT_FOUND = 'PathNotFound' + RENAME_DESTINATION_PARENT_PATH_NOT_FOUND = 'RenameDestinationParentPathNotFound' + SOURCE_PATH_NOT_FOUND = 'SourcePathNotFound' + DESTINATION_PATH_IS_BEING_DELETED = 'DestinationPathIsBeingDeleted' + FILE_SYSTEM_ALREADY_EXISTS = 'FilesystemAlreadyExists' + FILE_SYSTEM_BEING_DELETED = 'FilesystemBeingDeleted' + INVALID_DESTINATION_PATH = 'InvalidDestinationPath' + INVALID_RENAME_SOURCE_PATH = 'InvalidRenameSourcePath' + INVALID_SOURCE_OR_DESTINATION_RESOURCE_TYPE = 'InvalidSourceOrDestinationResourceType' + LEASE_IS_ALREADY_BROKEN = 'LeaseIsAlreadyBroken' + LEASE_NAME_MISMATCH = 'LeaseNameMismatch' + PATH_CONFLICT = 'PathConflict' + SOURCE_PATH_IS_BEING_DELETED = 'SourcePathIsBeingDeleted' + + +class DictMixin(object): + + def __setitem__(self, key, item): + self.__dict__[key] = item + + def __getitem__(self, key): + return self.__dict__[key] + + def __repr__(self): + return str(self) + + def __len__(self): + return len(self.keys()) + + def __delitem__(self, key): + self.__dict__[key] = None + + # Compare objects by comparing all attributes. + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.__dict__ == other.__dict__ + return False + + # Compare objects by comparing all attributes. + def __ne__(self, other): + return not self.__eq__(other) + + def __str__(self): + return str({k: v for k, v in self.__dict__.items() if not k.startswith('_')}) + + def __contains__(self, key): + return key in self.__dict__ + + def has_key(self, k): + return k in self.__dict__ + + def update(self, *args, **kwargs): + return self.__dict__.update(*args, **kwargs) + + def keys(self): + return [k for k in self.__dict__ if not k.startswith('_')] + + def values(self): + return [v for k, v in self.__dict__.items() if not k.startswith('_')] + + def items(self): + return [(k, v) for k, v in self.__dict__.items() if not k.startswith('_')] + + def get(self, key, default=None): + if key in self.__dict__: + return self.__dict__[key] + return default + + +class LocationMode(object): + """ + Specifies the location the request should be sent to. This mode only applies + for RA-GRS accounts which allow secondary read access. All other account types + must use PRIMARY. + """ + + PRIMARY = 'primary' #: Requests should be sent to the primary location. + SECONDARY = 'secondary' #: Requests should be sent to the secondary location, if possible. + + +class ResourceTypes(object): + """ + Specifies the resource types that are accessible with the account SAS. + + :param bool service: + Access to service-level APIs (e.g., Get/Set Service Properties, + Get Service Stats, List Containers/Queues/Shares) + :param bool container: + Access to container-level APIs (e.g., Create/Delete Container, + Create/Delete Queue, Create/Delete Share, + List Blobs/Files and Directories) + :param bool object: + Access to object-level APIs for blobs, queue messages, and + files(e.g. Put Blob, Query Entity, Get Messages, Create File, etc.) + """ + + service: bool = False + container: bool = False + object: bool = False + _str: str + + def __init__( + self, + service: bool = False, + container: bool = False, + object: bool = False # pylint: disable=redefined-builtin + ) -> None: + self.service = service + self.container = container + self.object = object + self._str = (('s' if self.service else '') + + ('c' if self.container else '') + + ('o' if self.object else '')) + + def __str__(self): + return self._str + + @classmethod + def from_string(cls, string): + """Create a ResourceTypes from a string. + + To specify service, container, or object you need only to + include the first letter of the word in the string. E.g. service and container, + you would provide a string "sc". + + :param str string: Specify service, container, or object in + in the string with the first letter of the word. + :return: A ResourceTypes object + :rtype: ~azure.storage.fileshare.ResourceTypes + """ + res_service = 's' in string + res_container = 'c' in string + res_object = 'o' in string + + parsed = cls(res_service, res_container, res_object) + parsed._str = string + return parsed + + +class AccountSasPermissions(object): + """ + :class:`~ResourceTypes` class to be used with generate_account_sas + function and for the AccessPolicies used with set_*_acl. There are two types of + SAS which may be used to grant resource access. One is to grant access to a + specific resource (resource-specific). Another is to grant access to the + entire service for a specific account and allow certain operations based on + perms found here. + + :param bool read: + Valid for all signed resources types (Service, Container, and Object). + Permits read permissions to the specified resource type. + :param bool write: + Valid for all signed resources types (Service, Container, and Object). + Permits write permissions to the specified resource type. + :param bool delete: + Valid for Container and Object resource types, except for queue messages. + :param bool delete_previous_version: + Delete the previous blob version for the versioning enabled storage account. + :param bool list: + Valid for Service and Container resource types only. + :param bool add: + Valid for the following Object resource types only: queue messages, and append blobs. + :param bool create: + Valid for the following Object resource types only: blobs and files. + Users can create new blobs or files, but may not overwrite existing + blobs or files. + :param bool update: + Valid for the following Object resource types only: queue messages. + :param bool process: + Valid for the following Object resource type only: queue messages. + :keyword bool tag: + To enable set or get tags on the blobs in the container. + :keyword bool filter_by_tags: + To enable get blobs by tags, this should be used together with list permission. + :keyword bool set_immutability_policy: + To enable operations related to set/delete immutability policy. + To get immutability policy, you just need read permission. + :keyword bool permanent_delete: + To enable permanent delete on the blob is permitted. + Valid for Object resource type of Blob only. + """ + + read: bool = False + write: bool = False + delete: bool = False + delete_previous_version: bool = False + list: bool = False + add: bool = False + create: bool = False + update: bool = False + process: bool = False + tag: bool = False + filter_by_tags: bool = False + set_immutability_policy: bool = False + permanent_delete: bool = False + + def __init__( + self, + read: bool = False, + write: bool = False, + delete: bool = False, + list: bool = False, # pylint: disable=redefined-builtin + add: bool = False, + create: bool = False, + update: bool = False, + process: bool = False, + delete_previous_version: bool = False, + **kwargs + ) -> None: + self.read = read + self.write = write + self.delete = delete + self.delete_previous_version = delete_previous_version + self.permanent_delete = kwargs.pop('permanent_delete', False) + self.list = list + self.add = add + self.create = create + self.update = update + self.process = process + self.tag = kwargs.pop('tag', False) + self.filter_by_tags = kwargs.pop('filter_by_tags', False) + self.set_immutability_policy = kwargs.pop('set_immutability_policy', False) + self._str = (('r' if self.read else '') + + ('w' if self.write else '') + + ('d' if self.delete else '') + + ('x' if self.delete_previous_version else '') + + ('y' if self.permanent_delete else '') + + ('l' if self.list else '') + + ('a' if self.add else '') + + ('c' if self.create else '') + + ('u' if self.update else '') + + ('p' if self.process else '') + + ('f' if self.filter_by_tags else '') + + ('t' if self.tag else '') + + ('i' if self.set_immutability_policy else '') + ) + + def __str__(self): + return self._str + + @classmethod + def from_string(cls, permission): + """Create AccountSasPermissions from a string. + + To specify read, write, delete, etc. permissions you need only to + include the first letter of the word in the string. E.g. for read and write + permissions you would provide a string "rw". + + :param str permission: Specify permissions in + the string with the first letter of the word. + :return: An AccountSasPermissions object + :rtype: ~azure.storage.fileshare.AccountSasPermissions + """ + p_read = 'r' in permission + p_write = 'w' in permission + p_delete = 'd' in permission + p_delete_previous_version = 'x' in permission + p_permanent_delete = 'y' in permission + p_list = 'l' in permission + p_add = 'a' in permission + p_create = 'c' in permission + p_update = 'u' in permission + p_process = 'p' in permission + p_tag = 't' in permission + p_filter_by_tags = 'f' in permission + p_set_immutability_policy = 'i' in permission + parsed = cls(read=p_read, write=p_write, delete=p_delete, delete_previous_version=p_delete_previous_version, + list=p_list, add=p_add, create=p_create, update=p_update, process=p_process, tag=p_tag, + filter_by_tags=p_filter_by_tags, set_immutability_policy=p_set_immutability_policy, + permanent_delete=p_permanent_delete) + + return parsed + + +class Services(object): + """Specifies the services accessible with the account SAS. + + :keyword bool blob: + Access for the `~azure.storage.blob.BlobServiceClient`. Default is False. + :keyword bool queue: + Access for the `~azure.storage.queue.QueueServiceClient`. Default is False. + :keyword bool fileshare: + Access for the `~azure.storage.fileshare.ShareServiceClient`. Default is False. + """ + + def __init__( + self, *, + blob: bool = False, + queue: bool = False, + fileshare: bool = False + ) -> None: + self.blob = blob + self.queue = queue + self.fileshare = fileshare + self._str = (('b' if self.blob else '') + + ('q' if self.queue else '') + + ('f' if self.fileshare else '')) + + def __str__(self): + return self._str + + @classmethod + def from_string(cls, string): + """Create Services from a string. + + To specify blob, queue, or file you need only to + include the first letter of the word in the string. E.g. for blob and queue + you would provide a string "bq". + + :param str string: Specify blob, queue, or file in + in the string with the first letter of the word. + :return: A Services object + :rtype: ~azure.storage.fileshare.Services + """ + res_blob = 'b' in string + res_queue = 'q' in string + res_file = 'f' in string + + parsed = cls(blob=res_blob, queue=res_queue, fileshare=res_file) + parsed._str = string + return parsed + + +class UserDelegationKey(object): + """ + Represents a user delegation key, provided to the user by Azure Storage + based on their Azure Active Directory access token. + + The fields are saved as simple strings since the user does not have to interact with this object; + to generate an identify SAS, the user can simply pass it to the right API. + """ + + signed_oid: Optional[str] = None + """Object ID of this token.""" + signed_tid: Optional[str] = None + """Tenant ID of the tenant that issued this token.""" + signed_start: Optional[str] = None + """The datetime this token becomes valid.""" + signed_expiry: Optional[str] = None + """The datetime this token expires.""" + signed_service: Optional[str] = None + """What service this key is valid for.""" + signed_version: Optional[str] = None + """The version identifier of the REST service that created this token.""" + value: Optional[str] = None + """The user delegation key.""" + + def __init__(self): + self.signed_oid = None + self.signed_tid = None + self.signed_start = None + self.signed_expiry = None + self.signed_service = None + self.signed_version = None + self.value = None + + +class StorageConfiguration(Configuration): + """ + Specifies the configurable values used in Azure Storage. + + :param int max_single_put_size: If the blob size is less than or equal max_single_put_size, then the blob will be + uploaded with only one http PUT request. If the blob size is larger than max_single_put_size, + the blob will be uploaded in chunks. Defaults to 64*1024*1024, or 64MB. + :param int copy_polling_interval: The interval in seconds for polling copy operations. + :param int max_block_size: The maximum chunk size for uploading a block blob in chunks. + Defaults to 4*1024*1024, or 4MB. + :param int min_large_block_upload_threshold: The minimum chunk size required to use the memory efficient + algorithm when uploading a block blob. + :param bool use_byte_buffer: Use a byte buffer for block blob uploads. Defaults to False. + :param int max_page_size: The maximum chunk size for uploading a page blob. Defaults to 4*1024*1024, or 4MB. + :param int min_large_chunk_upload_threshold: The max size for a single put operation. + :param int max_single_get_size: The maximum size for a blob to be downloaded in a single call, + the exceeded part will be downloaded in chunks (could be parallel). Defaults to 32*1024*1024, or 32MB. + :param int max_chunk_get_size: The maximum chunk size used for downloading a blob. Defaults to 4*1024*1024, + or 4MB. + :param int max_range_size: The max range size for file upload. + + """ + + max_single_put_size: int + copy_polling_interval: int + max_block_size: int + min_large_block_upload_threshold: int + use_byte_buffer: bool + max_page_size: int + min_large_chunk_upload_threshold: int + max_single_get_size: int + max_chunk_get_size: int + max_range_size: int + user_agent_policy: UserAgentPolicy + + def __init__(self, **kwargs): + super(StorageConfiguration, self).__init__(**kwargs) + self.max_single_put_size = kwargs.pop('max_single_put_size', 64 * 1024 * 1024) + self.copy_polling_interval = 15 + self.max_block_size = kwargs.pop('max_block_size', 4 * 1024 * 1024) + self.min_large_block_upload_threshold = kwargs.get('min_large_block_upload_threshold', 4 * 1024 * 1024 + 1) + self.use_byte_buffer = kwargs.pop('use_byte_buffer', False) + self.max_page_size = kwargs.pop('max_page_size', 4 * 1024 * 1024) + self.min_large_chunk_upload_threshold = kwargs.pop('min_large_chunk_upload_threshold', 100 * 1024 * 1024 + 1) + self.max_single_get_size = kwargs.pop('max_single_get_size', 32 * 1024 * 1024) + self.max_chunk_get_size = kwargs.pop('max_chunk_get_size', 4 * 1024 * 1024) + self.max_range_size = kwargs.pop('max_range_size', 4 * 1024 * 1024) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/parser.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/parser.py new file mode 100644 index 00000000..112c1984 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/parser.py @@ -0,0 +1,53 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from datetime import datetime, timezone +from typing import Optional + +EPOCH_AS_FILETIME = 116444736000000000 # January 1, 1970 as MS filetime +HUNDREDS_OF_NANOSECONDS = 10000000 + + +def _to_utc_datetime(value: datetime) -> str: + return value.strftime('%Y-%m-%dT%H:%M:%SZ') + + +def _rfc_1123_to_datetime(rfc_1123: str) -> Optional[datetime]: + """Converts an RFC 1123 date string to a UTC datetime. + + :param str rfc_1123: The time and date in RFC 1123 format. + :returns: The time and date in UTC datetime format. + :rtype: datetime + """ + if not rfc_1123: + return None + + return datetime.strptime(rfc_1123, "%a, %d %b %Y %H:%M:%S %Z") + + +def _filetime_to_datetime(filetime: str) -> Optional[datetime]: + """Converts an MS filetime string to a UTC datetime. "0" indicates None. + If parsing MS Filetime fails, tries RFC 1123 as backup. + + :param str filetime: The time and date in MS filetime format. + :returns: The time and date in UTC datetime format. + :rtype: datetime + """ + if not filetime: + return None + + # Try to convert to MS Filetime + try: + temp_filetime = int(filetime) + if temp_filetime == 0: + return None + + return datetime.fromtimestamp((temp_filetime - EPOCH_AS_FILETIME) / HUNDREDS_OF_NANOSECONDS, tz=timezone.utc) + except ValueError: + pass + + # Try RFC 1123 as backup + return _rfc_1123_to_datetime(filetime) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/policies.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/policies.py new file mode 100644 index 00000000..ee75cd5a --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/policies.py @@ -0,0 +1,694 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import base64 +import hashlib +import logging +import random +import re +import uuid +from io import SEEK_SET, UnsupportedOperation +from time import time +from typing import Any, Dict, Optional, TYPE_CHECKING +from urllib.parse import ( + parse_qsl, + urlencode, + urlparse, + urlunparse, +) +from wsgiref.handlers import format_date_time + +from azure.core.exceptions import AzureError, ServiceRequestError, ServiceResponseError +from azure.core.pipeline.policies import ( + BearerTokenCredentialPolicy, + HeadersPolicy, + HTTPPolicy, + NetworkTraceLoggingPolicy, + RequestHistory, + SansIOHTTPPolicy +) + +from .authentication import AzureSigningError, StorageHttpChallenge +from .constants import DEFAULT_OAUTH_SCOPE +from .models import LocationMode + +if TYPE_CHECKING: + from azure.core.credentials import TokenCredential + from azure.core.pipeline.transport import ( # pylint: disable=non-abstract-transport-import + PipelineRequest, + PipelineResponse + ) + + +_LOGGER = logging.getLogger(__name__) + + +def encode_base64(data): + if isinstance(data, str): + data = data.encode('utf-8') + encoded = base64.b64encode(data) + return encoded.decode('utf-8') + + +# Are we out of retries? +def is_exhausted(settings): + retry_counts = (settings['total'], settings['connect'], settings['read'], settings['status']) + retry_counts = list(filter(None, retry_counts)) + if not retry_counts: + return False + return min(retry_counts) < 0 + + +def retry_hook(settings, **kwargs): + if settings['hook']: + settings['hook'](retry_count=settings['count'] - 1, location_mode=settings['mode'], **kwargs) + + +# Is this method/status code retryable? (Based on allowlists and control +# variables such as the number of total retries to allow, whether to +# respect the Retry-After header, whether this header is present, and +# whether the returned status code is on the list of status codes to +# be retried upon on the presence of the aforementioned header) +def is_retry(response, mode): + status = response.http_response.status_code + if 300 <= status < 500: + # An exception occurred, but in most cases it was expected. Examples could + # include a 309 Conflict or 412 Precondition Failed. + if status == 404 and mode == LocationMode.SECONDARY: + # Response code 404 should be retried if secondary was used. + return True + if status == 408: + # Response code 408 is a timeout and should be retried. + return True + return False + if status >= 500: + # Response codes above 500 with the exception of 501 Not Implemented and + # 505 Version Not Supported indicate a server issue and should be retried. + if status in [501, 505]: + return False + return True + return False + + +def is_checksum_retry(response): + # retry if invalid content md5 + if response.context.get('validate_content', False) and response.http_response.headers.get('content-md5'): + computed_md5 = response.http_request.headers.get('content-md5', None) or \ + encode_base64(StorageContentValidation.get_content_md5(response.http_response.body())) + if response.http_response.headers['content-md5'] != computed_md5: + return True + return False + + +def urljoin(base_url, stub_url): + parsed = urlparse(base_url) + parsed = parsed._replace(path=parsed.path + '/' + stub_url) + return parsed.geturl() + + +class QueueMessagePolicy(SansIOHTTPPolicy): + + def on_request(self, request): + message_id = request.context.options.pop('queue_message_id', None) + if message_id: + request.http_request.url = urljoin( + request.http_request.url, + message_id) + + +class StorageHeadersPolicy(HeadersPolicy): + request_id_header_name = 'x-ms-client-request-id' + + def on_request(self, request: "PipelineRequest") -> None: + super(StorageHeadersPolicy, self).on_request(request) + current_time = format_date_time(time()) + request.http_request.headers['x-ms-date'] = current_time + + custom_id = request.context.options.pop('client_request_id', None) + request.http_request.headers['x-ms-client-request-id'] = custom_id or str(uuid.uuid1()) + + # def on_response(self, request, response): + # # raise exception if the echoed client request id from the service is not identical to the one we sent + # if self.request_id_header_name in response.http_response.headers: + + # client_request_id = request.http_request.headers.get(self.request_id_header_name) + + # if response.http_response.headers[self.request_id_header_name] != client_request_id: + # raise AzureError( + # "Echoed client request ID: {} does not match sent client request ID: {}. " + # "Service request ID: {}".format( + # response.http_response.headers[self.request_id_header_name], client_request_id, + # response.http_response.headers['x-ms-request-id']), + # response=response.http_response + # ) + + +class StorageHosts(SansIOHTTPPolicy): + + def __init__(self, hosts=None, **kwargs): # pylint: disable=unused-argument + self.hosts = hosts + super(StorageHosts, self).__init__() + + def on_request(self, request: "PipelineRequest") -> None: + request.context.options['hosts'] = self.hosts + parsed_url = urlparse(request.http_request.url) + + # Detect what location mode we're currently requesting with + location_mode = LocationMode.PRIMARY + for key, value in self.hosts.items(): + if parsed_url.netloc == value: + location_mode = key + + # See if a specific location mode has been specified, and if so, redirect + use_location = request.context.options.pop('use_location', None) + if use_location: + # Lock retries to the specific location + request.context.options['retry_to_secondary'] = False + if use_location not in self.hosts: + raise ValueError(f"Attempting to use undefined host location {use_location}") + if use_location != location_mode: + # Update request URL to use the specified location + updated = parsed_url._replace(netloc=self.hosts[use_location]) + request.http_request.url = updated.geturl() + location_mode = use_location + + request.context.options['location_mode'] = location_mode + + +class StorageLoggingPolicy(NetworkTraceLoggingPolicy): + """A policy that logs HTTP request and response to the DEBUG logger. + + This accepts both global configuration, and per-request level with "enable_http_logger" + """ + + def __init__(self, logging_enable: bool = False, **kwargs) -> None: + self.logging_body = kwargs.pop("logging_body", False) + super(StorageLoggingPolicy, self).__init__(logging_enable=logging_enable, **kwargs) + + def on_request(self, request: "PipelineRequest") -> None: + http_request = request.http_request + options = request.context.options + self.logging_body = self.logging_body or options.pop("logging_body", False) + if options.pop("logging_enable", self.enable_http_logger): + request.context["logging_enable"] = True + if not _LOGGER.isEnabledFor(logging.DEBUG): + return + + try: + log_url = http_request.url + query_params = http_request.query + if 'sig' in query_params: + log_url = log_url.replace(query_params['sig'], "sig=*****") + _LOGGER.debug("Request URL: %r", log_url) + _LOGGER.debug("Request method: %r", http_request.method) + _LOGGER.debug("Request headers:") + for header, value in http_request.headers.items(): + if header.lower() == 'authorization': + value = '*****' + elif header.lower() == 'x-ms-copy-source' and 'sig' in value: + # take the url apart and scrub away the signed signature + scheme, netloc, path, params, query, fragment = urlparse(value) + parsed_qs = dict(parse_qsl(query)) + parsed_qs['sig'] = '*****' + + # the SAS needs to be put back together + value = urlunparse((scheme, netloc, path, params, urlencode(parsed_qs), fragment)) + + _LOGGER.debug(" %r: %r", header, value) + _LOGGER.debug("Request body:") + + if self.logging_body: + _LOGGER.debug(str(http_request.body)) + else: + # We don't want to log the binary data of a file upload. + _LOGGER.debug("Hidden body, please use logging_body to show body") + except Exception as err: # pylint: disable=broad-except + _LOGGER.debug("Failed to log request: %r", err) + + def on_response(self, request: "PipelineRequest", response: "PipelineResponse") -> None: + if response.context.pop("logging_enable", self.enable_http_logger): + if not _LOGGER.isEnabledFor(logging.DEBUG): + return + + try: + _LOGGER.debug("Response status: %r", response.http_response.status_code) + _LOGGER.debug("Response headers:") + for res_header, value in response.http_response.headers.items(): + _LOGGER.debug(" %r: %r", res_header, value) + + # We don't want to log binary data if the response is a file. + _LOGGER.debug("Response content:") + pattern = re.compile(r'attachment; ?filename=["\w.]+', re.IGNORECASE) + header = response.http_response.headers.get('content-disposition') + resp_content_type = response.http_response.headers.get("content-type", "") + + if header and pattern.match(header): + filename = header.partition('=')[2] + _LOGGER.debug("File attachments: %s", filename) + elif resp_content_type.endswith("octet-stream"): + _LOGGER.debug("Body contains binary data.") + elif resp_content_type.startswith("image"): + _LOGGER.debug("Body contains image data.") + + if self.logging_body and resp_content_type.startswith("text"): + _LOGGER.debug(response.http_response.text()) + elif self.logging_body: + try: + _LOGGER.debug(response.http_response.body()) + except ValueError: + _LOGGER.debug("Body is streamable") + + except Exception as err: # pylint: disable=broad-except + _LOGGER.debug("Failed to log response: %s", repr(err)) + + +class StorageRequestHook(SansIOHTTPPolicy): + + def __init__(self, **kwargs): + self._request_callback = kwargs.get('raw_request_hook') + super(StorageRequestHook, self).__init__() + + def on_request(self, request: "PipelineRequest") -> None: + request_callback = request.context.options.pop('raw_request_hook', self._request_callback) + if request_callback: + request_callback(request) + + +class StorageResponseHook(HTTPPolicy): + + def __init__(self, **kwargs): + self._response_callback = kwargs.get('raw_response_hook') + super(StorageResponseHook, self).__init__() + + def send(self, request: "PipelineRequest") -> "PipelineResponse": + # Values could be 0 + data_stream_total = request.context.get('data_stream_total') + if data_stream_total is None: + data_stream_total = request.context.options.pop('data_stream_total', None) + download_stream_current = request.context.get('download_stream_current') + if download_stream_current is None: + download_stream_current = request.context.options.pop('download_stream_current', None) + upload_stream_current = request.context.get('upload_stream_current') + if upload_stream_current is None: + upload_stream_current = request.context.options.pop('upload_stream_current', None) + + response_callback = request.context.get('response_callback') or \ + request.context.options.pop('raw_response_hook', self._response_callback) + + response = self.next.send(request) + + will_retry = is_retry(response, request.context.options.get('mode')) or is_checksum_retry(response) + # Auth error could come from Bearer challenge, in which case this request will be made again + is_auth_error = response.http_response.status_code == 401 + should_update_counts = not (will_retry or is_auth_error) + + if should_update_counts and download_stream_current is not None: + download_stream_current += int(response.http_response.headers.get('Content-Length', 0)) + if data_stream_total is None: + content_range = response.http_response.headers.get('Content-Range') + if content_range: + data_stream_total = int(content_range.split(' ', 1)[1].split('/', 1)[1]) + else: + data_stream_total = download_stream_current + elif should_update_counts and upload_stream_current is not None: + upload_stream_current += int(response.http_request.headers.get('Content-Length', 0)) + for pipeline_obj in [request, response]: + if hasattr(pipeline_obj, 'context'): + pipeline_obj.context['data_stream_total'] = data_stream_total + pipeline_obj.context['download_stream_current'] = download_stream_current + pipeline_obj.context['upload_stream_current'] = upload_stream_current + if response_callback: + response_callback(response) + request.context['response_callback'] = response_callback + return response + + +class StorageContentValidation(SansIOHTTPPolicy): + """A simple policy that sends the given headers + with the request. + + This will overwrite any headers already defined in the request. + """ + header_name = 'Content-MD5' + + def __init__(self, **kwargs: Any) -> None: # pylint: disable=unused-argument + super(StorageContentValidation, self).__init__() + + @staticmethod + def get_content_md5(data): + # Since HTTP does not differentiate between no content and empty content, + # we have to perform a None check. + data = data or b"" + md5 = hashlib.md5() # nosec + if isinstance(data, bytes): + md5.update(data) + elif hasattr(data, 'read'): + pos = 0 + try: + pos = data.tell() + except: # pylint: disable=bare-except + pass + for chunk in iter(lambda: data.read(4096), b""): + md5.update(chunk) + try: + data.seek(pos, SEEK_SET) + except (AttributeError, IOError) as exc: + raise ValueError("Data should be bytes or a seekable file-like object.") from exc + else: + raise ValueError("Data should be bytes or a seekable file-like object.") + + return md5.digest() + + def on_request(self, request: "PipelineRequest") -> None: + validate_content = request.context.options.pop('validate_content', False) + if validate_content and request.http_request.method != 'GET': + computed_md5 = encode_base64(StorageContentValidation.get_content_md5(request.http_request.data)) + request.http_request.headers[self.header_name] = computed_md5 + request.context['validate_content_md5'] = computed_md5 + request.context['validate_content'] = validate_content + + def on_response(self, request: "PipelineRequest", response: "PipelineResponse") -> None: + if response.context.get('validate_content', False) and response.http_response.headers.get('content-md5'): + computed_md5 = request.context.get('validate_content_md5') or \ + encode_base64(StorageContentValidation.get_content_md5(response.http_response.body())) + if response.http_response.headers['content-md5'] != computed_md5: + raise AzureError(( + f"MD5 mismatch. Expected value is '{response.http_response.headers['content-md5']}', " + f"computed value is '{computed_md5}'."), + response=response.http_response + ) + + +class StorageRetryPolicy(HTTPPolicy): + """ + The base class for Exponential and Linear retries containing shared code. + """ + + total_retries: int + """The max number of retries.""" + connect_retries: int + """The max number of connect retries.""" + retry_read: int + """The max number of read retries.""" + retry_status: int + """The max number of status retries.""" + retry_to_secondary: bool + """Whether the secondary endpoint should be retried.""" + + def __init__(self, **kwargs: Any) -> None: + self.total_retries = kwargs.pop('retry_total', 10) + self.connect_retries = kwargs.pop('retry_connect', 3) + self.read_retries = kwargs.pop('retry_read', 3) + self.status_retries = kwargs.pop('retry_status', 3) + self.retry_to_secondary = kwargs.pop('retry_to_secondary', False) + super(StorageRetryPolicy, self).__init__() + + def _set_next_host_location(self, settings: Dict[str, Any], request: "PipelineRequest") -> None: + """ + A function which sets the next host location on the request, if applicable. + + :param Dict[str, Any]] settings: The configurable values pertaining to the next host location. + :param PipelineRequest request: A pipeline request object. + """ + if settings['hosts'] and all(settings['hosts'].values()): + url = urlparse(request.url) + # If there's more than one possible location, retry to the alternative + if settings['mode'] == LocationMode.PRIMARY: + settings['mode'] = LocationMode.SECONDARY + else: + settings['mode'] = LocationMode.PRIMARY + updated = url._replace(netloc=settings['hosts'].get(settings['mode'])) + request.url = updated.geturl() + + def configure_retries(self, request: "PipelineRequest") -> Dict[str, Any]: + body_position = None + if hasattr(request.http_request.body, 'read'): + try: + body_position = request.http_request.body.tell() + except (AttributeError, UnsupportedOperation): + # if body position cannot be obtained, then retries will not work + pass + options = request.context.options + return { + 'total': options.pop("retry_total", self.total_retries), + 'connect': options.pop("retry_connect", self.connect_retries), + 'read': options.pop("retry_read", self.read_retries), + 'status': options.pop("retry_status", self.status_retries), + 'retry_secondary': options.pop("retry_to_secondary", self.retry_to_secondary), + 'mode': options.pop("location_mode", LocationMode.PRIMARY), + 'hosts': options.pop("hosts", None), + 'hook': options.pop("retry_hook", None), + 'body_position': body_position, + 'count': 0, + 'history': [] + } + + def get_backoff_time(self, settings: Dict[str, Any]) -> float: # pylint: disable=unused-argument + """ Formula for computing the current backoff. + Should be calculated by child class. + + :param Dict[str, Any] settings: The configurable values pertaining to the backoff time. + :returns: The backoff time. + :rtype: float + """ + return 0 + + def sleep(self, settings, transport): + backoff = self.get_backoff_time(settings) + if not backoff or backoff < 0: + return + transport.sleep(backoff) + + def increment( + self, settings: Dict[str, Any], + request: "PipelineRequest", + response: Optional["PipelineResponse"] = None, + error: Optional[AzureError] = None + ) -> bool: + """Increment the retry counters. + + :param Dict[str, Any] settings: The configurable values pertaining to the increment operation. + :param PipelineRequest request: A pipeline request object. + :param Optional[PipelineResponse] response: A pipeline response object. + :param Optional[AzureError] error: An error encountered during the request, or + None if the response was received successfully. + :returns: Whether the retry attempts are exhausted. + :rtype: bool + """ + settings['total'] -= 1 + + if error and isinstance(error, ServiceRequestError): + # Errors when we're fairly sure that the server did not receive the + # request, so it should be safe to retry. + settings['connect'] -= 1 + settings['history'].append(RequestHistory(request, error=error)) + + elif error and isinstance(error, ServiceResponseError): + # Errors that occur after the request has been started, so we should + # assume that the server began processing it. + settings['read'] -= 1 + settings['history'].append(RequestHistory(request, error=error)) + + else: + # Incrementing because of a server error like a 500 in + # status_forcelist and a the given method is in the allowlist + if response: + settings['status'] -= 1 + settings['history'].append(RequestHistory(request, http_response=response)) + + if not is_exhausted(settings): + if request.method not in ['PUT'] and settings['retry_secondary']: + self._set_next_host_location(settings, request) + + # rewind the request body if it is a stream + if request.body and hasattr(request.body, 'read'): + # no position was saved, then retry would not work + if settings['body_position'] is None: + return False + try: + # attempt to rewind the body to the initial position + request.body.seek(settings['body_position'], SEEK_SET) + except (UnsupportedOperation, ValueError): + # if body is not seekable, then retry would not work + return False + settings['count'] += 1 + return True + return False + + def send(self, request): + retries_remaining = True + response = None + retry_settings = self.configure_retries(request) + while retries_remaining: + try: + response = self.next.send(request) + if is_retry(response, retry_settings['mode']) or is_checksum_retry(response): + retries_remaining = self.increment( + retry_settings, + request=request.http_request, + response=response.http_response) + if retries_remaining: + retry_hook( + retry_settings, + request=request.http_request, + response=response.http_response, + error=None) + self.sleep(retry_settings, request.context.transport) + continue + break + except AzureError as err: + if isinstance(err, AzureSigningError): + raise + retries_remaining = self.increment( + retry_settings, request=request.http_request, error=err) + if retries_remaining: + retry_hook( + retry_settings, + request=request.http_request, + response=None, + error=err) + self.sleep(retry_settings, request.context.transport) + continue + raise err + if retry_settings['history']: + response.context['history'] = retry_settings['history'] + response.http_response.location_mode = retry_settings['mode'] + return response + + +class ExponentialRetry(StorageRetryPolicy): + """Exponential retry.""" + + initial_backoff: int + """The initial backoff interval, in seconds, for the first retry.""" + increment_base: int + """The base, in seconds, to increment the initial_backoff by after the + first retry.""" + random_jitter_range: int + """A number in seconds which indicates a range to jitter/randomize for the back-off interval.""" + + def __init__( + self, initial_backoff: int = 15, + increment_base: int = 3, + retry_total: int = 3, + retry_to_secondary: bool = False, + random_jitter_range: int = 3, + **kwargs: Any + ) -> None: + """ + Constructs an Exponential retry object. The initial_backoff is used for + the first retry. Subsequent retries are retried after initial_backoff + + increment_power^retry_count seconds. + + :param int initial_backoff: + The initial backoff interval, in seconds, for the first retry. + :param int increment_base: + The base, in seconds, to increment the initial_backoff by after the + first retry. + :param int retry_total: + The maximum number of retry attempts. + :param bool retry_to_secondary: + Whether the request should be retried to secondary, if able. This should + only be enabled of RA-GRS accounts are used and potentially stale data + can be handled. + :param int random_jitter_range: + A number in seconds which indicates a range to jitter/randomize for the back-off interval. + For example, a random_jitter_range of 3 results in the back-off interval x to vary between x+3 and x-3. + """ + self.initial_backoff = initial_backoff + self.increment_base = increment_base + self.random_jitter_range = random_jitter_range + super(ExponentialRetry, self).__init__( + retry_total=retry_total, retry_to_secondary=retry_to_secondary, **kwargs) + + def get_backoff_time(self, settings: Dict[str, Any]) -> float: + """ + Calculates how long to sleep before retrying. + + :param Dict[str, Any]] settings: The configurable values pertaining to get backoff time. + :returns: + A float indicating how long to wait before retrying the request, + or None to indicate no retry should be performed. + :rtype: float + """ + random_generator = random.Random() + backoff = self.initial_backoff + (0 if settings['count'] == 0 else pow(self.increment_base, settings['count'])) + random_range_start = backoff - self.random_jitter_range if backoff > self.random_jitter_range else 0 + random_range_end = backoff + self.random_jitter_range + return random_generator.uniform(random_range_start, random_range_end) + + +class LinearRetry(StorageRetryPolicy): + """Linear retry.""" + + initial_backoff: int + """The backoff interval, in seconds, between retries.""" + random_jitter_range: int + """A number in seconds which indicates a range to jitter/randomize for the back-off interval.""" + + def __init__( + self, backoff: int = 15, + retry_total: int = 3, + retry_to_secondary: bool = False, + random_jitter_range: int = 3, + **kwargs: Any + ) -> None: + """ + Constructs a Linear retry object. + + :param int backoff: + The backoff interval, in seconds, between retries. + :param int retry_total: + The maximum number of retry attempts. + :param bool retry_to_secondary: + Whether the request should be retried to secondary, if able. This should + only be enabled of RA-GRS accounts are used and potentially stale data + can be handled. + :param int random_jitter_range: + A number in seconds which indicates a range to jitter/randomize for the back-off interval. + For example, a random_jitter_range of 3 results in the back-off interval x to vary between x+3 and x-3. + """ + self.backoff = backoff + self.random_jitter_range = random_jitter_range + super(LinearRetry, self).__init__( + retry_total=retry_total, retry_to_secondary=retry_to_secondary, **kwargs) + + def get_backoff_time(self, settings: Dict[str, Any]) -> float: + """ + Calculates how long to sleep before retrying. + + :param Dict[str, Any]] settings: The configurable values pertaining to the backoff time. + :returns: + A float indicating how long to wait before retrying the request, + or None to indicate no retry should be performed. + :rtype: float + """ + random_generator = random.Random() + # the backoff interval normally does not change, however there is the possibility + # that it was modified by accessing the property directly after initializing the object + random_range_start = self.backoff - self.random_jitter_range \ + if self.backoff > self.random_jitter_range else 0 + random_range_end = self.backoff + self.random_jitter_range + return random_generator.uniform(random_range_start, random_range_end) + + +class StorageBearerTokenCredentialPolicy(BearerTokenCredentialPolicy): + """ Custom Bearer token credential policy for following Storage Bearer challenges """ + + def __init__(self, credential: "TokenCredential", audience: str, **kwargs: Any) -> None: + super(StorageBearerTokenCredentialPolicy, self).__init__(credential, audience, **kwargs) + + def on_challenge(self, request: "PipelineRequest", response: "PipelineResponse") -> bool: + try: + auth_header = response.http_response.headers.get("WWW-Authenticate") + challenge = StorageHttpChallenge(auth_header) + except ValueError: + return False + + scope = challenge.resource_id + DEFAULT_OAUTH_SCOPE + self.authorize_request(request, scope, tenant_id=challenge.tenant_id) + + return True diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/policies_async.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/policies_async.py new file mode 100644 index 00000000..1c030a82 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/policies_async.py @@ -0,0 +1,296 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=invalid-overridden-method + +import asyncio +import logging +import random +from typing import Any, Dict, TYPE_CHECKING + +from azure.core.exceptions import AzureError, StreamClosedError, StreamConsumedError +from azure.core.pipeline.policies import AsyncBearerTokenCredentialPolicy, AsyncHTTPPolicy + +from .authentication import AzureSigningError, StorageHttpChallenge +from .constants import DEFAULT_OAUTH_SCOPE +from .policies import encode_base64, is_retry, StorageContentValidation, StorageRetryPolicy + +if TYPE_CHECKING: + from azure.core.credentials_async import AsyncTokenCredential + from azure.core.pipeline.transport import ( # pylint: disable=non-abstract-transport-import + PipelineRequest, + PipelineResponse + ) + + +_LOGGER = logging.getLogger(__name__) + + +async def retry_hook(settings, **kwargs): + if settings['hook']: + if asyncio.iscoroutine(settings['hook']): + await settings['hook']( + retry_count=settings['count'] - 1, + location_mode=settings['mode'], + **kwargs) + else: + settings['hook']( + retry_count=settings['count'] - 1, + location_mode=settings['mode'], + **kwargs) + + +async def is_checksum_retry(response): + # retry if invalid content md5 + if response.context.get('validate_content', False) and response.http_response.headers.get('content-md5'): + try: + await response.http_response.load_body() # Load the body in memory and close the socket + except (StreamClosedError, StreamConsumedError): + pass + computed_md5 = response.http_request.headers.get('content-md5', None) or \ + encode_base64(StorageContentValidation.get_content_md5(response.http_response.body())) + if response.http_response.headers['content-md5'] != computed_md5: + return True + return False + + +class AsyncStorageResponseHook(AsyncHTTPPolicy): + + def __init__(self, **kwargs): + self._response_callback = kwargs.get('raw_response_hook') + super(AsyncStorageResponseHook, self).__init__() + + async def send(self, request: "PipelineRequest") -> "PipelineResponse": + # Values could be 0 + data_stream_total = request.context.get('data_stream_total') + if data_stream_total is None: + data_stream_total = request.context.options.pop('data_stream_total', None) + download_stream_current = request.context.get('download_stream_current') + if download_stream_current is None: + download_stream_current = request.context.options.pop('download_stream_current', None) + upload_stream_current = request.context.get('upload_stream_current') + if upload_stream_current is None: + upload_stream_current = request.context.options.pop('upload_stream_current', None) + + response_callback = request.context.get('response_callback') or \ + request.context.options.pop('raw_response_hook', self._response_callback) + + response = await self.next.send(request) + + will_retry = is_retry(response, request.context.options.get('mode')) or await is_checksum_retry(response) + # Auth error could come from Bearer challenge, in which case this request will be made again + is_auth_error = response.http_response.status_code == 401 + should_update_counts = not (will_retry or is_auth_error) + + if should_update_counts and download_stream_current is not None: + download_stream_current += int(response.http_response.headers.get('Content-Length', 0)) + if data_stream_total is None: + content_range = response.http_response.headers.get('Content-Range') + if content_range: + data_stream_total = int(content_range.split(' ', 1)[1].split('/', 1)[1]) + else: + data_stream_total = download_stream_current + elif should_update_counts and upload_stream_current is not None: + upload_stream_current += int(response.http_request.headers.get('Content-Length', 0)) + for pipeline_obj in [request, response]: + if hasattr(pipeline_obj, 'context'): + pipeline_obj.context['data_stream_total'] = data_stream_total + pipeline_obj.context['download_stream_current'] = download_stream_current + pipeline_obj.context['upload_stream_current'] = upload_stream_current + if response_callback: + if asyncio.iscoroutine(response_callback): + await response_callback(response) # type: ignore + else: + response_callback(response) + request.context['response_callback'] = response_callback + return response + +class AsyncStorageRetryPolicy(StorageRetryPolicy): + """ + The base class for Exponential and Linear retries containing shared code. + """ + + async def sleep(self, settings, transport): + backoff = self.get_backoff_time(settings) + if not backoff or backoff < 0: + return + await transport.sleep(backoff) + + async def send(self, request): + retries_remaining = True + response = None + retry_settings = self.configure_retries(request) + while retries_remaining: + try: + response = await self.next.send(request) + if is_retry(response, retry_settings['mode']) or await is_checksum_retry(response): + retries_remaining = self.increment( + retry_settings, + request=request.http_request, + response=response.http_response) + if retries_remaining: + await retry_hook( + retry_settings, + request=request.http_request, + response=response.http_response, + error=None) + await self.sleep(retry_settings, request.context.transport) + continue + break + except AzureError as err: + if isinstance(err, AzureSigningError): + raise + retries_remaining = self.increment( + retry_settings, request=request.http_request, error=err) + if retries_remaining: + await retry_hook( + retry_settings, + request=request.http_request, + response=None, + error=err) + await self.sleep(retry_settings, request.context.transport) + continue + raise err + if retry_settings['history']: + response.context['history'] = retry_settings['history'] + response.http_response.location_mode = retry_settings['mode'] + return response + + +class ExponentialRetry(AsyncStorageRetryPolicy): + """Exponential retry.""" + + initial_backoff: int + """The initial backoff interval, in seconds, for the first retry.""" + increment_base: int + """The base, in seconds, to increment the initial_backoff by after the + first retry.""" + random_jitter_range: int + """A number in seconds which indicates a range to jitter/randomize for the back-off interval.""" + + def __init__( + self, + initial_backoff: int = 15, + increment_base: int = 3, + retry_total: int = 3, + retry_to_secondary: bool = False, + random_jitter_range: int = 3, **kwargs + ) -> None: + """ + Constructs an Exponential retry object. The initial_backoff is used for + the first retry. Subsequent retries are retried after initial_backoff + + increment_power^retry_count seconds. For example, by default the first retry + occurs after 15 seconds, the second after (15+3^1) = 18 seconds, and the + third after (15+3^2) = 24 seconds. + + :param int initial_backoff: + The initial backoff interval, in seconds, for the first retry. + :param int increment_base: + The base, in seconds, to increment the initial_backoff by after the + first retry. + :param int max_attempts: + The maximum number of retry attempts. + :param bool retry_to_secondary: + Whether the request should be retried to secondary, if able. This should + only be enabled of RA-GRS accounts are used and potentially stale data + can be handled. + :param int random_jitter_range: + A number in seconds which indicates a range to jitter/randomize for the back-off interval. + For example, a random_jitter_range of 3 results in the back-off interval x to vary between x+3 and x-3. + """ + self.initial_backoff = initial_backoff + self.increment_base = increment_base + self.random_jitter_range = random_jitter_range + super(ExponentialRetry, self).__init__( + retry_total=retry_total, retry_to_secondary=retry_to_secondary, **kwargs) + + def get_backoff_time(self, settings: Dict[str, Any]) -> float: + """ + Calculates how long to sleep before retrying. + + :param Dict[str, Any] settings: The configurable values pertaining to the backoff time. + :return: + An integer indicating how long to wait before retrying the request, + or None to indicate no retry should be performed. + :rtype: int or None + """ + random_generator = random.Random() + backoff = self.initial_backoff + (0 if settings['count'] == 0 else pow(self.increment_base, settings['count'])) + random_range_start = backoff - self.random_jitter_range if backoff > self.random_jitter_range else 0 + random_range_end = backoff + self.random_jitter_range + return random_generator.uniform(random_range_start, random_range_end) + + +class LinearRetry(AsyncStorageRetryPolicy): + """Linear retry.""" + + initial_backoff: int + """The backoff interval, in seconds, between retries.""" + random_jitter_range: int + """A number in seconds which indicates a range to jitter/randomize for the back-off interval.""" + + def __init__( + self, backoff: int = 15, + retry_total: int = 3, + retry_to_secondary: bool = False, + random_jitter_range: int = 3, + **kwargs: Any + ) -> None: + """ + Constructs a Linear retry object. + + :param int backoff: + The backoff interval, in seconds, between retries. + :param int max_attempts: + The maximum number of retry attempts. + :param bool retry_to_secondary: + Whether the request should be retried to secondary, if able. This should + only be enabled of RA-GRS accounts are used and potentially stale data + can be handled. + :param int random_jitter_range: + A number in seconds which indicates a range to jitter/randomize for the back-off interval. + For example, a random_jitter_range of 3 results in the back-off interval x to vary between x+3 and x-3. + """ + self.backoff = backoff + self.random_jitter_range = random_jitter_range + super(LinearRetry, self).__init__( + retry_total=retry_total, retry_to_secondary=retry_to_secondary, **kwargs) + + def get_backoff_time(self, settings: Dict[str, Any]) -> float: + """ + Calculates how long to sleep before retrying. + + :param Dict[str, Any] settings: The configurable values pertaining to the backoff time. + :return: + An integer indicating how long to wait before retrying the request, + or None to indicate no retry should be performed. + :rtype: int or None + """ + random_generator = random.Random() + # the backoff interval normally does not change, however there is the possibility + # that it was modified by accessing the property directly after initializing the object + random_range_start = self.backoff - self.random_jitter_range \ + if self.backoff > self.random_jitter_range else 0 + random_range_end = self.backoff + self.random_jitter_range + return random_generator.uniform(random_range_start, random_range_end) + + +class AsyncStorageBearerTokenCredentialPolicy(AsyncBearerTokenCredentialPolicy): + """ Custom Bearer token credential policy for following Storage Bearer challenges """ + + def __init__(self, credential: "AsyncTokenCredential", audience: str, **kwargs: Any) -> None: + super(AsyncStorageBearerTokenCredentialPolicy, self).__init__(credential, audience, **kwargs) + + async def on_challenge(self, request: "PipelineRequest", response: "PipelineResponse") -> bool: + try: + auth_header = response.http_response.headers.get("WWW-Authenticate") + challenge = StorageHttpChallenge(auth_header) + except ValueError: + return False + + scope = challenge.resource_id + DEFAULT_OAUTH_SCOPE + await self.authorize_request(request, scope, tenant_id=challenge.tenant_id) + + return True diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/request_handlers.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/request_handlers.py new file mode 100644 index 00000000..54927cc7 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/request_handlers.py @@ -0,0 +1,270 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import logging +import stat +from io import (SEEK_END, SEEK_SET, UnsupportedOperation) +from os import fstat +from typing import Dict, Optional + +import isodate + + +_LOGGER = logging.getLogger(__name__) + +_REQUEST_DELIMITER_PREFIX = "batch_" +_HTTP1_1_IDENTIFIER = "HTTP/1.1" +_HTTP_LINE_ENDING = "\r\n" + + +def serialize_iso(attr): + """Serialize Datetime object into ISO-8601 formatted string. + + :param Datetime attr: Object to be serialized. + :rtype: str + :raises: ValueError if format invalid. + """ + if not attr: + return None + if isinstance(attr, str): + attr = isodate.parse_datetime(attr) + try: + utc = attr.utctimetuple() + if utc.tm_year > 9999 or utc.tm_year < 1: + raise OverflowError("Hit max or min date") + + date = f"{utc.tm_year:04}-{utc.tm_mon:02}-{utc.tm_mday:02}T{utc.tm_hour:02}:{utc.tm_min:02}:{utc.tm_sec:02}" + return date + 'Z' + except (ValueError, OverflowError) as err: + raise ValueError("Unable to serialize datetime object.") from err + except AttributeError as err: + raise TypeError("ISO-8601 object must be valid datetime object.") from err + +def get_length(data): + length = None + # Check if object implements the __len__ method, covers most input cases such as bytearray. + try: + length = len(data) + except: # pylint: disable=bare-except + pass + + if not length: + # Check if the stream is a file-like stream object. + # If so, calculate the size using the file descriptor. + try: + fileno = data.fileno() + except (AttributeError, UnsupportedOperation): + pass + else: + try: + mode = fstat(fileno).st_mode + if stat.S_ISREG(mode) or stat.S_ISLNK(mode): + #st_size only meaningful if regular file or symlink, other types + # e.g. sockets may return misleading sizes like 0 + return fstat(fileno).st_size + except OSError: + # Not a valid fileno, may be possible requests returned + # a socket number? + pass + + # If the stream is seekable and tell() is implemented, calculate the stream size. + try: + current_position = data.tell() + data.seek(0, SEEK_END) + length = data.tell() - current_position + data.seek(current_position, SEEK_SET) + except (AttributeError, OSError, UnsupportedOperation): + pass + + return length + + +def read_length(data): + try: + if hasattr(data, 'read'): + read_data = b'' + for chunk in iter(lambda: data.read(4096), b""): + read_data += chunk + return len(read_data), read_data + if hasattr(data, '__iter__'): + read_data = b'' + for chunk in data: + read_data += chunk + return len(read_data), read_data + except: # pylint: disable=bare-except + pass + raise ValueError("Unable to calculate content length, please specify.") + + +def validate_and_format_range_headers( + start_range, end_range, start_range_required=True, + end_range_required=True, check_content_md5=False, align_to_page=False): + # If end range is provided, start range must be provided + if (start_range_required or end_range is not None) and start_range is None: + raise ValueError("start_range value cannot be None.") + if end_range_required and end_range is None: + raise ValueError("end_range value cannot be None.") + + # Page ranges must be 512 aligned + if align_to_page: + if start_range is not None and start_range % 512 != 0: + raise ValueError(f"Invalid page blob start_range: {start_range}. " + "The size must be aligned to a 512-byte boundary.") + if end_range is not None and end_range % 512 != 511: + raise ValueError(f"Invalid page blob end_range: {end_range}. " + "The size must be aligned to a 512-byte boundary.") + + # Format based on whether end_range is present + range_header = None + if end_range is not None: + range_header = f'bytes={start_range}-{end_range}' + elif start_range is not None: + range_header = f"bytes={start_range}-" + + # Content MD5 can only be provided for a complete range less than 4MB in size + range_validation = None + if check_content_md5: + if start_range is None or end_range is None: + raise ValueError("Both start and end range required for MD5 content validation.") + if end_range - start_range > 4 * 1024 * 1024: + raise ValueError("Getting content MD5 for a range greater than 4MB is not supported.") + range_validation = 'true' + + return range_header, range_validation + + +def add_metadata_headers(metadata=None): + # type: (Optional[Dict[str, str]]) -> Dict[str, str] + headers = {} + if metadata: + for key, value in metadata.items(): + headers[f'x-ms-meta-{key.strip()}'] = value.strip() if value else value + return headers + + +def serialize_batch_body(requests, batch_id): + """ + --<delimiter> + <subrequest> + --<delimiter> + <subrequest> (repeated as needed) + --<delimiter>-- + + Serializes the requests in this batch to a single HTTP mixed/multipart body. + + :param List[~azure.core.pipeline.transport.HttpRequest] requests: + a list of sub-request for the batch request + :param str batch_id: + to be embedded in batch sub-request delimiter + :returns: The body bytes for this batch. + :rtype: bytes + """ + + if requests is None or len(requests) == 0: + raise ValueError('Please provide sub-request(s) for this batch request') + + delimiter_bytes = (_get_batch_request_delimiter(batch_id, True, False) + _HTTP_LINE_ENDING).encode('utf-8') + newline_bytes = _HTTP_LINE_ENDING.encode('utf-8') + batch_body = [] + + content_index = 0 + for request in requests: + request.headers.update({ + "Content-ID": str(content_index), + "Content-Length": str(0) + }) + batch_body.append(delimiter_bytes) + batch_body.append(_make_body_from_sub_request(request)) + batch_body.append(newline_bytes) + content_index += 1 + + batch_body.append(_get_batch_request_delimiter(batch_id, True, True).encode('utf-8')) + # final line of body MUST have \r\n at the end, or it will not be properly read by the service + batch_body.append(newline_bytes) + + return b"".join(batch_body) + + +def _get_batch_request_delimiter(batch_id, is_prepend_dashes=False, is_append_dashes=False): + """ + Gets the delimiter used for this batch request's mixed/multipart HTTP format. + + :param str batch_id: + Randomly generated id + :param bool is_prepend_dashes: + Whether to include the starting dashes. Used in the body, but non on defining the delimiter. + :param bool is_append_dashes: + Whether to include the ending dashes. Used in the body on the closing delimiter only. + :returns: The delimiter, WITHOUT a trailing newline. + :rtype: str + """ + + prepend_dashes = '--' if is_prepend_dashes else '' + append_dashes = '--' if is_append_dashes else '' + + return prepend_dashes + _REQUEST_DELIMITER_PREFIX + batch_id + append_dashes + + +def _make_body_from_sub_request(sub_request): + """ + Content-Type: application/http + Content-ID: <sequential int ID> + Content-Transfer-Encoding: <value> (if present) + + <verb> <path><query> HTTP/<version> + <header key>: <header value> (repeated as necessary) + Content-Length: <value> + (newline if content length > 0) + <body> (if content length > 0) + + Serializes an http request. + + :param ~azure.core.pipeline.transport.HttpRequest sub_request: + Request to serialize. + :returns: The serialized sub-request in bytes + :rtype: bytes + """ + + # put the sub-request's headers into a list for efficient str concatenation + sub_request_body = [] + + # get headers for ease of manipulation; remove headers as they are used + headers = sub_request.headers + + # append opening headers + sub_request_body.append("Content-Type: application/http") + sub_request_body.append(_HTTP_LINE_ENDING) + + sub_request_body.append("Content-ID: ") + sub_request_body.append(headers.pop("Content-ID", "")) + sub_request_body.append(_HTTP_LINE_ENDING) + + sub_request_body.append("Content-Transfer-Encoding: binary") + sub_request_body.append(_HTTP_LINE_ENDING) + + # append blank line + sub_request_body.append(_HTTP_LINE_ENDING) + + # append HTTP verb and path and query and HTTP version + sub_request_body.append(sub_request.method) + sub_request_body.append(' ') + sub_request_body.append(sub_request.url) + sub_request_body.append(' ') + sub_request_body.append(_HTTP1_1_IDENTIFIER) + sub_request_body.append(_HTTP_LINE_ENDING) + + # append remaining headers (this will set the Content-Length, as it was set on `sub-request`) + for header_name, header_value in headers.items(): + if header_value is not None: + sub_request_body.append(header_name) + sub_request_body.append(": ") + sub_request_body.append(header_value) + sub_request_body.append(_HTTP_LINE_ENDING) + + # append blank line + sub_request_body.append(_HTTP_LINE_ENDING) + + return ''.join(sub_request_body).encode() diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/response_handlers.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/response_handlers.py new file mode 100644 index 00000000..af9a2fcd --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/response_handlers.py @@ -0,0 +1,200 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +import logging +from typing import NoReturn +from xml.etree.ElementTree import Element + +from azure.core.exceptions import ( + ClientAuthenticationError, + DecodeError, + HttpResponseError, + ResourceExistsError, + ResourceModifiedError, + ResourceNotFoundError, +) +from azure.core.pipeline.policies import ContentDecodePolicy + +from .authentication import AzureSigningError +from .models import get_enum_value, StorageErrorCode, UserDelegationKey +from .parser import _to_utc_datetime + + +_LOGGER = logging.getLogger(__name__) + + +class PartialBatchErrorException(HttpResponseError): + """There is a partial failure in batch operations. + + :param str message: The message of the exception. + :param response: Server response to be deserialized. + :param list parts: A list of the parts in multipart response. + """ + + def __init__(self, message, response, parts): + self.parts = parts + super(PartialBatchErrorException, self).__init__(message=message, response=response) + + +# Parses the blob length from the content range header: bytes 1-3/65537 +def parse_length_from_content_range(content_range): + if content_range is None: + return None + + # First, split in space and take the second half: '1-3/65537' + # Next, split on slash and take the second half: '65537' + # Finally, convert to an int: 65537 + return int(content_range.split(' ', 1)[1].split('/', 1)[1]) + + +def normalize_headers(headers): + normalized = {} + for key, value in headers.items(): + if key.startswith('x-ms-'): + key = key[5:] + normalized[key.lower().replace('-', '_')] = get_enum_value(value) + return normalized + + +def deserialize_metadata(response, obj, headers): # pylint: disable=unused-argument + try: + raw_metadata = {k: v for k, v in response.http_response.headers.items() if k.lower().startswith('x-ms-meta-')} + except AttributeError: + raw_metadata = {k: v for k, v in response.headers.items() if k.lower().startswith('x-ms-meta-')} + return {k[10:]: v for k, v in raw_metadata.items()} + + +def return_response_headers(response, deserialized, response_headers): # pylint: disable=unused-argument + return normalize_headers(response_headers) + + +def return_headers_and_deserialized(response, deserialized, response_headers): # pylint: disable=unused-argument + return normalize_headers(response_headers), deserialized + + +def return_context_and_deserialized(response, deserialized, response_headers): # pylint: disable=unused-argument + return response.http_response.location_mode, deserialized + + +def return_raw_deserialized(response, *_): + return response.http_response.location_mode, response.context[ContentDecodePolicy.CONTEXT_NAME] + + +def process_storage_error(storage_error) -> NoReturn: # type: ignore [misc] # pylint:disable=too-many-statements, too-many-branches + raise_error = HttpResponseError + serialized = False + if isinstance(storage_error, AzureSigningError): + storage_error.message = storage_error.message + \ + '. This is likely due to an invalid shared key. Please check your shared key and try again.' + if not storage_error.response or storage_error.response.status_code in [200, 204]: + raise storage_error + # If it is one of those three then it has been serialized prior by the generated layer. + if isinstance(storage_error, (PartialBatchErrorException, + ClientAuthenticationError, ResourceNotFoundError, ResourceExistsError)): + serialized = True + error_code = storage_error.response.headers.get('x-ms-error-code') + error_message = storage_error.message + additional_data = {} + error_dict = {} + try: + error_body = ContentDecodePolicy.deserialize_from_http_generics(storage_error.response) + try: + if error_body is None or len(error_body) == 0: + error_body = storage_error.response.reason + except AttributeError: + error_body = '' + # If it is an XML response + if isinstance(error_body, Element): + error_dict = { + child.tag.lower(): child.text + for child in error_body + } + # If it is a JSON response + elif isinstance(error_body, dict): + error_dict = error_body.get('error', {}) + elif not error_code: + _LOGGER.warning( + 'Unexpected return type %s from ContentDecodePolicy.deserialize_from_http_generics.', type(error_body)) + error_dict = {'message': str(error_body)} + + # If we extracted from a Json or XML response + # There is a chance error_dict is just a string + if error_dict and isinstance(error_dict, dict): + error_code = error_dict.get('code') + error_message = error_dict.get('message') + additional_data = {k: v for k, v in error_dict.items() if k not in {'code', 'message'}} + except DecodeError: + pass + + try: + # This check would be unnecessary if we have already serialized the error + if error_code and not serialized: + error_code = StorageErrorCode(error_code) + if error_code in [StorageErrorCode.condition_not_met, + StorageErrorCode.blob_overwritten]: + raise_error = ResourceModifiedError + if error_code in [StorageErrorCode.invalid_authentication_info, + StorageErrorCode.authentication_failed]: + raise_error = ClientAuthenticationError + if error_code in [StorageErrorCode.resource_not_found, + StorageErrorCode.cannot_verify_copy_source, + StorageErrorCode.blob_not_found, + StorageErrorCode.queue_not_found, + StorageErrorCode.container_not_found, + StorageErrorCode.parent_not_found, + StorageErrorCode.share_not_found]: + raise_error = ResourceNotFoundError + if error_code in [StorageErrorCode.account_already_exists, + StorageErrorCode.account_being_created, + StorageErrorCode.resource_already_exists, + StorageErrorCode.resource_type_mismatch, + StorageErrorCode.blob_already_exists, + StorageErrorCode.queue_already_exists, + StorageErrorCode.container_already_exists, + StorageErrorCode.container_being_deleted, + StorageErrorCode.queue_being_deleted, + StorageErrorCode.share_already_exists, + StorageErrorCode.share_being_deleted]: + raise_error = ResourceExistsError + except ValueError: + # Got an unknown error code + pass + + # Error message should include all the error properties + try: + error_message += f"\nErrorCode:{error_code.value}" + except AttributeError: + error_message += f"\nErrorCode:{error_code}" + for name, info in additional_data.items(): + error_message += f"\n{name}:{info}" + + # No need to create an instance if it has already been serialized by the generated layer + if serialized: + storage_error.message = error_message + error = storage_error + else: + error = raise_error(message=error_message, response=storage_error.response) + # Ensure these properties are stored in the error instance as well (not just the error message) + error.error_code = error_code + error.additional_info = additional_data + # error.args is what's surfaced on the traceback - show error message in all cases + error.args = (error.message,) + try: + # `from None` prevents us from double printing the exception (suppresses generated layer error context) + exec("raise error from None") # pylint: disable=exec-used # nosec + except SyntaxError as exc: + raise error from exc + + +def parse_to_internal_user_delegation_key(service_user_delegation_key): + internal_user_delegation_key = UserDelegationKey() + internal_user_delegation_key.signed_oid = service_user_delegation_key.signed_oid + internal_user_delegation_key.signed_tid = service_user_delegation_key.signed_tid + internal_user_delegation_key.signed_start = _to_utc_datetime(service_user_delegation_key.signed_start) + internal_user_delegation_key.signed_expiry = _to_utc_datetime(service_user_delegation_key.signed_expiry) + internal_user_delegation_key.signed_service = service_user_delegation_key.signed_service + internal_user_delegation_key.signed_version = service_user_delegation_key.signed_version + internal_user_delegation_key.value = service_user_delegation_key.value + return internal_user_delegation_key diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/shared_access_signature.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/shared_access_signature.py new file mode 100644 index 00000000..2ef9921d --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/shared_access_signature.py @@ -0,0 +1,243 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from datetime import date + +from .parser import _to_utc_datetime +from .constants import X_MS_VERSION +from . import sign_string, url_quote + +# cspell:ignoreRegExp rsc. +# cspell:ignoreRegExp s..?id +class QueryStringConstants(object): + SIGNED_SIGNATURE = 'sig' + SIGNED_PERMISSION = 'sp' + SIGNED_START = 'st' + SIGNED_EXPIRY = 'se' + SIGNED_RESOURCE = 'sr' + SIGNED_IDENTIFIER = 'si' + SIGNED_IP = 'sip' + SIGNED_PROTOCOL = 'spr' + SIGNED_VERSION = 'sv' + SIGNED_CACHE_CONTROL = 'rscc' + SIGNED_CONTENT_DISPOSITION = 'rscd' + SIGNED_CONTENT_ENCODING = 'rsce' + SIGNED_CONTENT_LANGUAGE = 'rscl' + SIGNED_CONTENT_TYPE = 'rsct' + START_PK = 'spk' + START_RK = 'srk' + END_PK = 'epk' + END_RK = 'erk' + SIGNED_RESOURCE_TYPES = 'srt' + SIGNED_SERVICES = 'ss' + SIGNED_OID = 'skoid' + SIGNED_TID = 'sktid' + SIGNED_KEY_START = 'skt' + SIGNED_KEY_EXPIRY = 'ske' + SIGNED_KEY_SERVICE = 'sks' + SIGNED_KEY_VERSION = 'skv' + SIGNED_ENCRYPTION_SCOPE = 'ses' + + # for ADLS + SIGNED_AUTHORIZED_OID = 'saoid' + SIGNED_UNAUTHORIZED_OID = 'suoid' + SIGNED_CORRELATION_ID = 'scid' + SIGNED_DIRECTORY_DEPTH = 'sdd' + + @staticmethod + def to_list(): + return [ + QueryStringConstants.SIGNED_SIGNATURE, + QueryStringConstants.SIGNED_PERMISSION, + QueryStringConstants.SIGNED_START, + QueryStringConstants.SIGNED_EXPIRY, + QueryStringConstants.SIGNED_RESOURCE, + QueryStringConstants.SIGNED_IDENTIFIER, + QueryStringConstants.SIGNED_IP, + QueryStringConstants.SIGNED_PROTOCOL, + QueryStringConstants.SIGNED_VERSION, + QueryStringConstants.SIGNED_CACHE_CONTROL, + QueryStringConstants.SIGNED_CONTENT_DISPOSITION, + QueryStringConstants.SIGNED_CONTENT_ENCODING, + QueryStringConstants.SIGNED_CONTENT_LANGUAGE, + QueryStringConstants.SIGNED_CONTENT_TYPE, + QueryStringConstants.START_PK, + QueryStringConstants.START_RK, + QueryStringConstants.END_PK, + QueryStringConstants.END_RK, + QueryStringConstants.SIGNED_RESOURCE_TYPES, + QueryStringConstants.SIGNED_SERVICES, + QueryStringConstants.SIGNED_OID, + QueryStringConstants.SIGNED_TID, + QueryStringConstants.SIGNED_KEY_START, + QueryStringConstants.SIGNED_KEY_EXPIRY, + QueryStringConstants.SIGNED_KEY_SERVICE, + QueryStringConstants.SIGNED_KEY_VERSION, + QueryStringConstants.SIGNED_ENCRYPTION_SCOPE, + # for ADLS + QueryStringConstants.SIGNED_AUTHORIZED_OID, + QueryStringConstants.SIGNED_UNAUTHORIZED_OID, + QueryStringConstants.SIGNED_CORRELATION_ID, + QueryStringConstants.SIGNED_DIRECTORY_DEPTH, + ] + + +class SharedAccessSignature(object): + ''' + Provides a factory for creating account access + signature tokens with an account name and account key. Users can either + use the factory or can construct the appropriate service and use the + generate_*_shared_access_signature method directly. + ''' + + def __init__(self, account_name, account_key, x_ms_version=X_MS_VERSION): + ''' + :param str account_name: + The storage account name used to generate the shared access signatures. + :param str account_key: + The access key to generate the shares access signatures. + :param str x_ms_version: + The service version used to generate the shared access signatures. + ''' + self.account_name = account_name + self.account_key = account_key + self.x_ms_version = x_ms_version + + def generate_account( + self, services, + resource_types, + permission, + expiry, + start=None, + ip=None, + protocol=None, + sts_hook=None + ) -> str: + ''' + Generates a shared access signature for the account. + Use the returned signature with the sas_token parameter of the service + or to create a new account object. + + :param Any services: The specified services associated with the shared access signature. + :param ResourceTypes resource_types: + Specifies the resource types that are accessible with the account + SAS. You can combine values to provide access to more than one + resource type. + :param AccountSasPermissions permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has been + specified in an associated stored access policy. You can combine + values to provide more than one permission. + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: datetime or str + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. The provided datetime will always + be interpreted as UTC. + :type start: datetime or str + :param str ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS + restricts the request to those IP addresses. + :param str protocol: + Specifies the protocol permitted for a request made. The default value + is https,http. See :class:`~azure.storage.common.models.Protocol` for possible values. + :param sts_hook: + For debugging purposes only. If provided, the hook is called with the string to sign + that was used to generate the SAS. + :type sts_hook: Optional[Callable[[str], None]] + :returns: The generated SAS token for the account. + :rtype: str + ''' + sas = _SharedAccessHelper() + sas.add_base(permission, expiry, start, ip, protocol, self.x_ms_version) + sas.add_account(services, resource_types) + sas.add_account_signature(self.account_name, self.account_key) + + if sts_hook is not None: + sts_hook(sas.string_to_sign) + + return sas.get_token() + + +class _SharedAccessHelper(object): + def __init__(self): + self.query_dict = {} + self.string_to_sign = "" + + def _add_query(self, name, val): + if val: + self.query_dict[name] = str(val) if val is not None else None + + def add_base(self, permission, expiry, start, ip, protocol, x_ms_version): + if isinstance(start, date): + start = _to_utc_datetime(start) + + if isinstance(expiry, date): + expiry = _to_utc_datetime(expiry) + + self._add_query(QueryStringConstants.SIGNED_START, start) + self._add_query(QueryStringConstants.SIGNED_EXPIRY, expiry) + self._add_query(QueryStringConstants.SIGNED_PERMISSION, permission) + self._add_query(QueryStringConstants.SIGNED_IP, ip) + self._add_query(QueryStringConstants.SIGNED_PROTOCOL, protocol) + self._add_query(QueryStringConstants.SIGNED_VERSION, x_ms_version) + + def add_resource(self, resource): + self._add_query(QueryStringConstants.SIGNED_RESOURCE, resource) + + def add_id(self, policy_id): + self._add_query(QueryStringConstants.SIGNED_IDENTIFIER, policy_id) + + def add_account(self, services, resource_types): + self._add_query(QueryStringConstants.SIGNED_SERVICES, services) + self._add_query(QueryStringConstants.SIGNED_RESOURCE_TYPES, resource_types) + + def add_override_response_headers(self, cache_control, + content_disposition, + content_encoding, + content_language, + content_type): + self._add_query(QueryStringConstants.SIGNED_CACHE_CONTROL, cache_control) + self._add_query(QueryStringConstants.SIGNED_CONTENT_DISPOSITION, content_disposition) + self._add_query(QueryStringConstants.SIGNED_CONTENT_ENCODING, content_encoding) + self._add_query(QueryStringConstants.SIGNED_CONTENT_LANGUAGE, content_language) + self._add_query(QueryStringConstants.SIGNED_CONTENT_TYPE, content_type) + + def add_account_signature(self, account_name, account_key): + def get_value_to_append(query): + return_value = self.query_dict.get(query) or '' + return return_value + '\n' + + self.string_to_sign = \ + (account_name + '\n' + + get_value_to_append(QueryStringConstants.SIGNED_PERMISSION) + + get_value_to_append(QueryStringConstants.SIGNED_SERVICES) + + get_value_to_append(QueryStringConstants.SIGNED_RESOURCE_TYPES) + + get_value_to_append(QueryStringConstants.SIGNED_START) + + get_value_to_append(QueryStringConstants.SIGNED_EXPIRY) + + get_value_to_append(QueryStringConstants.SIGNED_IP) + + get_value_to_append(QueryStringConstants.SIGNED_PROTOCOL) + + get_value_to_append(QueryStringConstants.SIGNED_VERSION) + + '\n' # Signed Encryption Scope - always empty for fileshare + ) + + self._add_query(QueryStringConstants.SIGNED_SIGNATURE, + sign_string(account_key, self.string_to_sign)) + + def get_token(self) -> str: + return '&'.join([f'{n}={url_quote(v)}' for n, v in self.query_dict.items() if v is not None]) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/uploads.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/uploads.py new file mode 100644 index 00000000..b31cfb32 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/uploads.py @@ -0,0 +1,604 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from concurrent import futures +from io import BytesIO, IOBase, SEEK_CUR, SEEK_END, SEEK_SET, UnsupportedOperation +from itertools import islice +from math import ceil +from threading import Lock + +from azure.core.tracing.common import with_current_context + +from .import encode_base64, url_quote +from .request_handlers import get_length +from .response_handlers import return_response_headers + + +_LARGE_BLOB_UPLOAD_MAX_READ_BUFFER_SIZE = 4 * 1024 * 1024 +_ERROR_VALUE_SHOULD_BE_SEEKABLE_STREAM = "{0} should be a seekable file-like/io.IOBase type stream object." + + +def _parallel_uploads(executor, uploader, pending, running): + range_ids = [] + while True: + # Wait for some download to finish before adding a new one + done, running = futures.wait(running, return_when=futures.FIRST_COMPLETED) + range_ids.extend([chunk.result() for chunk in done]) + try: + for _ in range(0, len(done)): + next_chunk = next(pending) + running.add(executor.submit(with_current_context(uploader), next_chunk)) + except StopIteration: + break + + # Wait for the remaining uploads to finish + done, _running = futures.wait(running) + range_ids.extend([chunk.result() for chunk in done]) + return range_ids + + +def upload_data_chunks( + service=None, + uploader_class=None, + total_size=None, + chunk_size=None, + max_concurrency=None, + stream=None, + validate_content=None, + progress_hook=None, + **kwargs): + + parallel = max_concurrency > 1 + if parallel and 'modified_access_conditions' in kwargs: + # Access conditions do not work with parallelism + kwargs['modified_access_conditions'] = None + + uploader = uploader_class( + service=service, + total_size=total_size, + chunk_size=chunk_size, + stream=stream, + parallel=parallel, + validate_content=validate_content, + progress_hook=progress_hook, + **kwargs) + if parallel: + with futures.ThreadPoolExecutor(max_concurrency) as executor: + upload_tasks = uploader.get_chunk_streams() + running_futures = [ + executor.submit(with_current_context(uploader.process_chunk), u) + for u in islice(upload_tasks, 0, max_concurrency) + ] + range_ids = _parallel_uploads(executor, uploader.process_chunk, upload_tasks, running_futures) + else: + range_ids = [uploader.process_chunk(result) for result in uploader.get_chunk_streams()] + if any(range_ids): + return [r[1] for r in sorted(range_ids, key=lambda r: r[0])] + return uploader.response_headers + + +def upload_substream_blocks( + service=None, + uploader_class=None, + total_size=None, + chunk_size=None, + max_concurrency=None, + stream=None, + progress_hook=None, + **kwargs): + parallel = max_concurrency > 1 + if parallel and 'modified_access_conditions' in kwargs: + # Access conditions do not work with parallelism + kwargs['modified_access_conditions'] = None + uploader = uploader_class( + service=service, + total_size=total_size, + chunk_size=chunk_size, + stream=stream, + parallel=parallel, + progress_hook=progress_hook, + **kwargs) + + if parallel: + with futures.ThreadPoolExecutor(max_concurrency) as executor: + upload_tasks = uploader.get_substream_blocks() + running_futures = [ + executor.submit(with_current_context(uploader.process_substream_block), u) + for u in islice(upload_tasks, 0, max_concurrency) + ] + range_ids = _parallel_uploads(executor, uploader.process_substream_block, upload_tasks, running_futures) + else: + range_ids = [uploader.process_substream_block(b) for b in uploader.get_substream_blocks()] + if any(range_ids): + return sorted(range_ids) + return [] + + +class _ChunkUploader(object): # pylint: disable=too-many-instance-attributes + + def __init__( + self, service, + total_size, + chunk_size, + stream, + parallel, + encryptor=None, + padder=None, + progress_hook=None, + **kwargs): + self.service = service + self.total_size = total_size + self.chunk_size = chunk_size + self.stream = stream + self.parallel = parallel + + # Stream management + self.stream_lock = Lock() if parallel else None + + # Progress feedback + self.progress_total = 0 + self.progress_lock = Lock() if parallel else None + self.progress_hook = progress_hook + + # Encryption + self.encryptor = encryptor + self.padder = padder + self.response_headers = None + self.etag = None + self.last_modified = None + self.request_options = kwargs + + def get_chunk_streams(self): + index = 0 + while True: + data = b"" + read_size = self.chunk_size + + # Buffer until we either reach the end of the stream or get a whole chunk. + while True: + if self.total_size: + read_size = min(self.chunk_size - len(data), self.total_size - (index + len(data))) + temp = self.stream.read(read_size) + if not isinstance(temp, bytes): + raise TypeError("Blob data should be of type bytes.") + data += temp or b"" + + # We have read an empty string and so are at the end + # of the buffer or we have read a full chunk. + if temp == b"" or len(data) == self.chunk_size: + break + + if len(data) == self.chunk_size: + if self.padder: + data = self.padder.update(data) + if self.encryptor: + data = self.encryptor.update(data) + yield index, data + else: + if self.padder: + data = self.padder.update(data) + self.padder.finalize() + if self.encryptor: + data = self.encryptor.update(data) + self.encryptor.finalize() + if data: + yield index, data + break + index += len(data) + + def process_chunk(self, chunk_data): + chunk_bytes = chunk_data[1] + chunk_offset = chunk_data[0] + return self._upload_chunk_with_progress(chunk_offset, chunk_bytes) + + def _update_progress(self, length): + if self.progress_lock is not None: + with self.progress_lock: + self.progress_total += length + else: + self.progress_total += length + + if self.progress_hook: + self.progress_hook(self.progress_total, self.total_size) + + def _upload_chunk(self, chunk_offset, chunk_data): + raise NotImplementedError("Must be implemented by child class.") + + def _upload_chunk_with_progress(self, chunk_offset, chunk_data): + range_id = self._upload_chunk(chunk_offset, chunk_data) + self._update_progress(len(chunk_data)) + return range_id + + def get_substream_blocks(self): + assert self.chunk_size is not None + lock = self.stream_lock + blob_length = self.total_size + + if blob_length is None: + blob_length = get_length(self.stream) + if blob_length is None: + raise ValueError("Unable to determine content length of upload data.") + + blocks = int(ceil(blob_length / (self.chunk_size * 1.0))) + last_block_size = self.chunk_size if blob_length % self.chunk_size == 0 else blob_length % self.chunk_size + + for i in range(blocks): + index = i * self.chunk_size + length = last_block_size if i == blocks - 1 else self.chunk_size + yield index, SubStream(self.stream, index, length, lock) + + def process_substream_block(self, block_data): + return self._upload_substream_block_with_progress(block_data[0], block_data[1]) + + def _upload_substream_block(self, index, block_stream): + raise NotImplementedError("Must be implemented by child class.") + + def _upload_substream_block_with_progress(self, index, block_stream): + range_id = self._upload_substream_block(index, block_stream) + self._update_progress(len(block_stream)) + return range_id + + def set_response_properties(self, resp): + self.etag = resp.etag + self.last_modified = resp.last_modified + + +class BlockBlobChunkUploader(_ChunkUploader): + + def __init__(self, *args, **kwargs): + kwargs.pop("modified_access_conditions", None) + super(BlockBlobChunkUploader, self).__init__(*args, **kwargs) + self.current_length = None + + def _upload_chunk(self, chunk_offset, chunk_data): + # TODO: This is incorrect, but works with recording. + index = f'{chunk_offset:032d}' + block_id = encode_base64(url_quote(encode_base64(index))) + self.service.stage_block( + block_id, + len(chunk_data), + chunk_data, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options + ) + return index, block_id + + def _upload_substream_block(self, index, block_stream): + try: + block_id = f'BlockId{(index//self.chunk_size):05}' + self.service.stage_block( + block_id, + len(block_stream), + block_stream, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options + ) + finally: + block_stream.close() + return block_id + + +class PageBlobChunkUploader(_ChunkUploader): + + def _is_chunk_empty(self, chunk_data): + # read until non-zero byte is encountered + # if reached the end without returning, then chunk_data is all 0's + return not any(bytearray(chunk_data)) + + def _upload_chunk(self, chunk_offset, chunk_data): + # avoid uploading the empty pages + if not self._is_chunk_empty(chunk_data): + chunk_end = chunk_offset + len(chunk_data) - 1 + content_range = f"bytes={chunk_offset}-{chunk_end}" + computed_md5 = None + self.response_headers = self.service.upload_pages( + body=chunk_data, + content_length=len(chunk_data), + transactional_content_md5=computed_md5, + range=content_range, + cls=return_response_headers, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options + ) + + if not self.parallel and self.request_options.get('modified_access_conditions'): + self.request_options['modified_access_conditions'].if_match = self.response_headers['etag'] + + def _upload_substream_block(self, index, block_stream): + pass + + +class AppendBlobChunkUploader(_ChunkUploader): + + def __init__(self, *args, **kwargs): + super(AppendBlobChunkUploader, self).__init__(*args, **kwargs) + self.current_length = None + + def _upload_chunk(self, chunk_offset, chunk_data): + if self.current_length is None: + self.response_headers = self.service.append_block( + body=chunk_data, + content_length=len(chunk_data), + cls=return_response_headers, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options + ) + self.current_length = int(self.response_headers["blob_append_offset"]) + else: + self.request_options['append_position_access_conditions'].append_position = \ + self.current_length + chunk_offset + self.response_headers = self.service.append_block( + body=chunk_data, + content_length=len(chunk_data), + cls=return_response_headers, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options + ) + + def _upload_substream_block(self, index, block_stream): + pass + + +class DataLakeFileChunkUploader(_ChunkUploader): + + def _upload_chunk(self, chunk_offset, chunk_data): + # avoid uploading the empty pages + self.response_headers = self.service.append_data( + body=chunk_data, + position=chunk_offset, + content_length=len(chunk_data), + cls=return_response_headers, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options + ) + + if not self.parallel and self.request_options.get('modified_access_conditions'): + self.request_options['modified_access_conditions'].if_match = self.response_headers['etag'] + + def _upload_substream_block(self, index, block_stream): + try: + self.service.append_data( + body=block_stream, + position=index, + content_length=len(block_stream), + cls=return_response_headers, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options + ) + finally: + block_stream.close() + + +class FileChunkUploader(_ChunkUploader): + + def _upload_chunk(self, chunk_offset, chunk_data): + length = len(chunk_data) + chunk_end = chunk_offset + length - 1 + response = self.service.upload_range( + chunk_data, + chunk_offset, + length, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options + ) + return f'bytes={chunk_offset}-{chunk_end}', response + + # TODO: Implement this method. + def _upload_substream_block(self, index, block_stream): + pass + + +class SubStream(IOBase): + + def __init__(self, wrapped_stream, stream_begin_index, length, lockObj): + # Python 2.7: file-like objects created with open() typically support seek(), but are not + # derivations of io.IOBase and thus do not implement seekable(). + # Python > 3.0: file-like objects created with open() are derived from io.IOBase. + try: + # only the main thread runs this, so there's no need grabbing the lock + wrapped_stream.seek(0, SEEK_CUR) + except Exception as exc: + raise ValueError("Wrapped stream must support seek().") from exc + + self._lock = lockObj + self._wrapped_stream = wrapped_stream + self._position = 0 + self._stream_begin_index = stream_begin_index + self._length = length + self._buffer = BytesIO() + + # we must avoid buffering more than necessary, and also not use up too much memory + # so the max buffer size is capped at 4MB + self._max_buffer_size = ( + length if length < _LARGE_BLOB_UPLOAD_MAX_READ_BUFFER_SIZE else _LARGE_BLOB_UPLOAD_MAX_READ_BUFFER_SIZE + ) + self._current_buffer_start = 0 + self._current_buffer_size = 0 + super(SubStream, self).__init__() + + def __len__(self): + return self._length + + def close(self): + if self._buffer: + self._buffer.close() + self._wrapped_stream = None + IOBase.close(self) + + def fileno(self): + return self._wrapped_stream.fileno() + + def flush(self): + pass + + def read(self, size=None): + if self.closed: # pylint: disable=using-constant-test + raise ValueError("Stream is closed.") + + if size is None: + size = self._length - self._position + + # adjust if out of bounds + if size + self._position >= self._length: + size = self._length - self._position + + # return fast + if size == 0 or self._buffer.closed: + return b"" + + # attempt first read from the read buffer and update position + read_buffer = self._buffer.read(size) + bytes_read = len(read_buffer) + bytes_remaining = size - bytes_read + self._position += bytes_read + + # repopulate the read buffer from the underlying stream to fulfill the request + # ensure the seek and read operations are done atomically (only if a lock is provided) + if bytes_remaining > 0: + with self._buffer: + # either read in the max buffer size specified on the class + # or read in just enough data for the current block/sub stream + current_max_buffer_size = min(self._max_buffer_size, self._length - self._position) + + # lock is only defined if max_concurrency > 1 (parallel uploads) + if self._lock: + with self._lock: + # reposition the underlying stream to match the start of the data to read + absolute_position = self._stream_begin_index + self._position + self._wrapped_stream.seek(absolute_position, SEEK_SET) + # If we can't seek to the right location, our read will be corrupted so fail fast. + if self._wrapped_stream.tell() != absolute_position: + raise IOError("Stream failed to seek to the desired location.") + buffer_from_stream = self._wrapped_stream.read(current_max_buffer_size) + else: + absolute_position = self._stream_begin_index + self._position + # It's possible that there's connection problem during data transfer, + # so when we retry we don't want to read from current position of wrapped stream, + # instead we should seek to where we want to read from. + if self._wrapped_stream.tell() != absolute_position: + self._wrapped_stream.seek(absolute_position, SEEK_SET) + + buffer_from_stream = self._wrapped_stream.read(current_max_buffer_size) + + if buffer_from_stream: + # update the buffer with new data from the wrapped stream + # we need to note down the start position and size of the buffer, in case seek is performed later + self._buffer = BytesIO(buffer_from_stream) + self._current_buffer_start = self._position + self._current_buffer_size = len(buffer_from_stream) + + # read the remaining bytes from the new buffer and update position + second_read_buffer = self._buffer.read(bytes_remaining) + read_buffer += second_read_buffer + self._position += len(second_read_buffer) + + return read_buffer + + def readable(self): + return True + + def readinto(self, b): + raise UnsupportedOperation + + def seek(self, offset, whence=0): + if whence is SEEK_SET: + start_index = 0 + elif whence is SEEK_CUR: + start_index = self._position + elif whence is SEEK_END: + start_index = self._length + offset = -offset + else: + raise ValueError("Invalid argument for the 'whence' parameter.") + + pos = start_index + offset + + if pos > self._length: + pos = self._length + elif pos < 0: + pos = 0 + + # check if buffer is still valid + # if not, drop buffer + if pos < self._current_buffer_start or pos >= self._current_buffer_start + self._current_buffer_size: + self._buffer.close() + self._buffer = BytesIO() + else: # if yes seek to correct position + delta = pos - self._current_buffer_start + self._buffer.seek(delta, SEEK_SET) + + self._position = pos + return pos + + def seekable(self): + return True + + def tell(self): + return self._position + + def write(self): + raise UnsupportedOperation + + def writelines(self): + raise UnsupportedOperation + + def writeable(self): + return False + + +class IterStreamer(object): + """ + File-like streaming iterator. + """ + + def __init__(self, generator, encoding="UTF-8"): + self.generator = generator + self.iterator = iter(generator) + self.leftover = b"" + self.encoding = encoding + + def __len__(self): + return self.generator.__len__() + + def __iter__(self): + return self.iterator + + def seekable(self): + return False + + def __next__(self): + return next(self.iterator) + + def tell(self, *args, **kwargs): + raise UnsupportedOperation("Data generator does not support tell.") + + def seek(self, *args, **kwargs): + raise UnsupportedOperation("Data generator is not seekable.") + + def read(self, size): + data = self.leftover + count = len(self.leftover) + try: + while count < size: + chunk = self.__next__() + if isinstance(chunk, str): + chunk = chunk.encode(self.encoding) + data += chunk + count += len(chunk) + # This means count < size and what's leftover will be returned in this call. + except StopIteration: + self.leftover = b"" + + if count >= size: + self.leftover = data[size:] + + return data[:size] diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/uploads_async.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/uploads_async.py new file mode 100644 index 00000000..3e102ec5 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared/uploads_async.py @@ -0,0 +1,460 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +import asyncio +import inspect +import threading +from asyncio import Lock +from io import UnsupportedOperation +from itertools import islice +from math import ceil +from typing import AsyncGenerator, Union + +from .import encode_base64, url_quote +from .request_handlers import get_length +from .response_handlers import return_response_headers +from .uploads import SubStream, IterStreamer # pylint: disable=unused-import + + +async def _async_parallel_uploads(uploader, pending, running): + range_ids = [] + while True: + # Wait for some download to finish before adding a new one + done, running = await asyncio.wait(running, return_when=asyncio.FIRST_COMPLETED) + range_ids.extend([chunk.result() for chunk in done]) + try: + for _ in range(0, len(done)): + next_chunk = await pending.__anext__() + running.add(asyncio.ensure_future(uploader(next_chunk))) + except StopAsyncIteration: + break + + # Wait for the remaining uploads to finish + if running: + done, _running = await asyncio.wait(running) + range_ids.extend([chunk.result() for chunk in done]) + return range_ids + + +async def _parallel_uploads(uploader, pending, running): + range_ids = [] + while True: + # Wait for some download to finish before adding a new one + done, running = await asyncio.wait(running, return_when=asyncio.FIRST_COMPLETED) + range_ids.extend([chunk.result() for chunk in done]) + try: + for _ in range(0, len(done)): + next_chunk = next(pending) + running.add(asyncio.ensure_future(uploader(next_chunk))) + except StopIteration: + break + + # Wait for the remaining uploads to finish + if running: + done, _running = await asyncio.wait(running) + range_ids.extend([chunk.result() for chunk in done]) + return range_ids + + +async def upload_data_chunks( + service=None, + uploader_class=None, + total_size=None, + chunk_size=None, + max_concurrency=None, + stream=None, + progress_hook=None, + **kwargs): + + parallel = max_concurrency > 1 + if parallel and 'modified_access_conditions' in kwargs: + # Access conditions do not work with parallelism + kwargs['modified_access_conditions'] = None + + uploader = uploader_class( + service=service, + total_size=total_size, + chunk_size=chunk_size, + stream=stream, + parallel=parallel, + progress_hook=progress_hook, + **kwargs) + + if parallel: + upload_tasks = uploader.get_chunk_streams() + running_futures = [] + for _ in range(max_concurrency): + try: + chunk = await upload_tasks.__anext__() + running_futures.append(asyncio.ensure_future(uploader.process_chunk(chunk))) + except StopAsyncIteration: + break + + range_ids = await _async_parallel_uploads(uploader.process_chunk, upload_tasks, running_futures) + else: + range_ids = [] + async for chunk in uploader.get_chunk_streams(): + range_ids.append(await uploader.process_chunk(chunk)) + + if any(range_ids): + return [r[1] for r in sorted(range_ids, key=lambda r: r[0])] + return uploader.response_headers + + +async def upload_substream_blocks( + service=None, + uploader_class=None, + total_size=None, + chunk_size=None, + max_concurrency=None, + stream=None, + progress_hook=None, + **kwargs): + parallel = max_concurrency > 1 + if parallel and 'modified_access_conditions' in kwargs: + # Access conditions do not work with parallelism + kwargs['modified_access_conditions'] = None + uploader = uploader_class( + service=service, + total_size=total_size, + chunk_size=chunk_size, + stream=stream, + parallel=parallel, + progress_hook=progress_hook, + **kwargs) + + if parallel: + upload_tasks = uploader.get_substream_blocks() + running_futures = [ + asyncio.ensure_future(uploader.process_substream_block(u)) + for u in islice(upload_tasks, 0, max_concurrency) + ] + range_ids = await _parallel_uploads(uploader.process_substream_block, upload_tasks, running_futures) + else: + range_ids = [] + for block in uploader.get_substream_blocks(): + range_ids.append(await uploader.process_substream_block(block)) + if any(range_ids): + return sorted(range_ids) + return + + +class _ChunkUploader(object): # pylint: disable=too-many-instance-attributes + + def __init__( + self, service, + total_size, + chunk_size, + stream, + parallel, + encryptor=None, + padder=None, + progress_hook=None, + **kwargs): + self.service = service + self.total_size = total_size + self.chunk_size = chunk_size + self.stream = stream + self.parallel = parallel + + # Stream management + self.stream_lock = threading.Lock() if parallel else None + + # Progress feedback + self.progress_total = 0 + self.progress_lock = Lock() if parallel else None + self.progress_hook = progress_hook + + # Encryption + self.encryptor = encryptor + self.padder = padder + self.response_headers = None + self.etag = None + self.last_modified = None + self.request_options = kwargs + + async def get_chunk_streams(self): + index = 0 + while True: + data = b'' + read_size = self.chunk_size + + # Buffer until we either reach the end of the stream or get a whole chunk. + while True: + if self.total_size: + read_size = min(self.chunk_size - len(data), self.total_size - (index + len(data))) + temp = self.stream.read(read_size) + if inspect.isawaitable(temp): + temp = await temp + if not isinstance(temp, bytes): + raise TypeError('Blob data should be of type bytes.') + data += temp or b"" + + # We have read an empty string and so are at the end + # of the buffer or we have read a full chunk. + if temp == b'' or len(data) == self.chunk_size: + break + + if len(data) == self.chunk_size: + if self.padder: + data = self.padder.update(data) + if self.encryptor: + data = self.encryptor.update(data) + yield index, data + else: + if self.padder: + data = self.padder.update(data) + self.padder.finalize() + if self.encryptor: + data = self.encryptor.update(data) + self.encryptor.finalize() + if data: + yield index, data + break + index += len(data) + + async def process_chunk(self, chunk_data): + chunk_bytes = chunk_data[1] + chunk_offset = chunk_data[0] + return await self._upload_chunk_with_progress(chunk_offset, chunk_bytes) + + async def _update_progress(self, length): + if self.progress_lock is not None: + async with self.progress_lock: + self.progress_total += length + else: + self.progress_total += length + + if self.progress_hook: + await self.progress_hook(self.progress_total, self.total_size) + + async def _upload_chunk(self, chunk_offset, chunk_data): + raise NotImplementedError("Must be implemented by child class.") + + async def _upload_chunk_with_progress(self, chunk_offset, chunk_data): + range_id = await self._upload_chunk(chunk_offset, chunk_data) + await self._update_progress(len(chunk_data)) + return range_id + + def get_substream_blocks(self): + assert self.chunk_size is not None + lock = self.stream_lock + blob_length = self.total_size + + if blob_length is None: + blob_length = get_length(self.stream) + if blob_length is None: + raise ValueError("Unable to determine content length of upload data.") + + blocks = int(ceil(blob_length / (self.chunk_size * 1.0))) + last_block_size = self.chunk_size if blob_length % self.chunk_size == 0 else blob_length % self.chunk_size + + for i in range(blocks): + index = i * self.chunk_size + length = last_block_size if i == blocks - 1 else self.chunk_size + yield index, SubStream(self.stream, index, length, lock) + + async def process_substream_block(self, block_data): + return await self._upload_substream_block_with_progress(block_data[0], block_data[1]) + + async def _upload_substream_block(self, index, block_stream): + raise NotImplementedError("Must be implemented by child class.") + + async def _upload_substream_block_with_progress(self, index, block_stream): + range_id = await self._upload_substream_block(index, block_stream) + await self._update_progress(len(block_stream)) + return range_id + + def set_response_properties(self, resp): + self.etag = resp.etag + self.last_modified = resp.last_modified + + +class BlockBlobChunkUploader(_ChunkUploader): + + def __init__(self, *args, **kwargs): + kwargs.pop('modified_access_conditions', None) + super(BlockBlobChunkUploader, self).__init__(*args, **kwargs) + self.current_length = None + + async def _upload_chunk(self, chunk_offset, chunk_data): + # TODO: This is incorrect, but works with recording. + index = f'{chunk_offset:032d}' + block_id = encode_base64(url_quote(encode_base64(index))) + await self.service.stage_block( + block_id, + len(chunk_data), + body=chunk_data, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options) + return index, block_id + + async def _upload_substream_block(self, index, block_stream): + try: + block_id = f'BlockId{(index//self.chunk_size):05}' + await self.service.stage_block( + block_id, + len(block_stream), + block_stream, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options) + finally: + block_stream.close() + return block_id + + +class PageBlobChunkUploader(_ChunkUploader): + + def _is_chunk_empty(self, chunk_data): + # read until non-zero byte is encountered + # if reached the end without returning, then chunk_data is all 0's + for each_byte in chunk_data: + if each_byte not in [0, b'\x00']: + return False + return True + + async def _upload_chunk(self, chunk_offset, chunk_data): + # avoid uploading the empty pages + if not self._is_chunk_empty(chunk_data): + chunk_end = chunk_offset + len(chunk_data) - 1 + content_range = f'bytes={chunk_offset}-{chunk_end}' + computed_md5 = None + self.response_headers = await self.service.upload_pages( + body=chunk_data, + content_length=len(chunk_data), + transactional_content_md5=computed_md5, + range=content_range, + cls=return_response_headers, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options) + + if not self.parallel and self.request_options.get('modified_access_conditions'): + self.request_options['modified_access_conditions'].if_match = self.response_headers['etag'] + + async def _upload_substream_block(self, index, block_stream): + pass + + +class AppendBlobChunkUploader(_ChunkUploader): + + def __init__(self, *args, **kwargs): + super(AppendBlobChunkUploader, self).__init__(*args, **kwargs) + self.current_length = None + + async def _upload_chunk(self, chunk_offset, chunk_data): + if self.current_length is None: + self.response_headers = await self.service.append_block( + body=chunk_data, + content_length=len(chunk_data), + cls=return_response_headers, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options) + self.current_length = int(self.response_headers['blob_append_offset']) + else: + self.request_options['append_position_access_conditions'].append_position = \ + self.current_length + chunk_offset + self.response_headers = await self.service.append_block( + body=chunk_data, + content_length=len(chunk_data), + cls=return_response_headers, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options) + + async def _upload_substream_block(self, index, block_stream): + pass + + +class DataLakeFileChunkUploader(_ChunkUploader): + + async def _upload_chunk(self, chunk_offset, chunk_data): + self.response_headers = await self.service.append_data( + body=chunk_data, + position=chunk_offset, + content_length=len(chunk_data), + cls=return_response_headers, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options + ) + + if not self.parallel and self.request_options.get('modified_access_conditions'): + self.request_options['modified_access_conditions'].if_match = self.response_headers['etag'] + + async def _upload_substream_block(self, index, block_stream): + try: + await self.service.append_data( + body=block_stream, + position=index, + content_length=len(block_stream), + cls=return_response_headers, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options + ) + finally: + block_stream.close() + + +class FileChunkUploader(_ChunkUploader): + + async def _upload_chunk(self, chunk_offset, chunk_data): + length = len(chunk_data) + chunk_end = chunk_offset + length - 1 + response = await self.service.upload_range( + chunk_data, + chunk_offset, + length, + data_stream_total=self.total_size, + upload_stream_current=self.progress_total, + **self.request_options + ) + range_id = f'bytes={chunk_offset}-{chunk_end}' + return range_id, response + + # TODO: Implement this method. + async def _upload_substream_block(self, index, block_stream): + pass + + +class AsyncIterStreamer(): + """ + File-like streaming object for AsyncGenerators. + """ + def __init__(self, generator: AsyncGenerator[Union[bytes, str], None], encoding: str = "UTF-8"): + self.iterator = generator.__aiter__() + self.leftover = b"" + self.encoding = encoding + + def seekable(self): + return False + + def tell(self, *args, **kwargs): + raise UnsupportedOperation("Data generator does not support tell.") + + def seek(self, *args, **kwargs): + raise UnsupportedOperation("Data generator is not seekable.") + + async def read(self, size: int) -> bytes: + data = self.leftover + count = len(self.leftover) + try: + while count < size: + chunk = await self.iterator.__anext__() + if isinstance(chunk, str): + chunk = chunk.encode(self.encoding) + data += chunk + count += len(chunk) + # This means count < size and what's leftover will be returned in this call. + except StopAsyncIteration: + self.leftover = b"" + + if count >= size: + self.leftover = data[size:] + + return data[:size] diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared_access_signature.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared_access_signature.py new file mode 100644 index 00000000..24679c72 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_shared_access_signature.py @@ -0,0 +1,574 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=docstring-keyword-should-match-keyword-only + +from typing import ( + Any, Callable, List, Optional, Union, + TYPE_CHECKING +) +from urllib.parse import parse_qs + +from ._shared import sign_string +from ._shared.constants import X_MS_VERSION +from ._shared.models import Services +from ._shared.shared_access_signature import QueryStringConstants, SharedAccessSignature, _SharedAccessHelper + +if TYPE_CHECKING: + from datetime import datetime + from azure.storage.fileshare import ( + AccountSasPermissions, + FileSasPermissions, + ShareSasPermissions, + ResourceTypes + ) + + +class FileSharedAccessSignature(SharedAccessSignature): + """ + Provides a factory for creating file and share access + signature tokens with a common account name and account key. Users can either + use the factory or can construct the appropriate service and use the + generate_*_shared_access_signature method directly. + """ + + def __init__(self, account_name: str, account_key: str) -> None: + """ + :param str account_name: + The storage account name used to generate the shared access signatures. + :param str account_key: + The access key to generate the shares access signatures. + """ + super(FileSharedAccessSignature, self).__init__(account_name, account_key, x_ms_version=X_MS_VERSION) + + def generate_file( + self, share_name: str, + directory_name: Optional[str] = None, + file_name: Optional[str] = None, + permission: Optional[Union["FileSasPermissions", str]] = None, + expiry: Optional[Union["datetime", str]] = None, + start: Optional[Union["datetime", str]] = None, + policy_id: Optional[str] = None, + ip: Optional[str] = None, + protocol: Optional[str] = None, + cache_control: Optional[str] = None, + content_disposition: Optional[str] = None, + content_encoding: Optional[str] = None, + content_language: Optional[str] = None, + content_type: Optional[str] = None, + sts_hook: Optional[Callable[[str], None]] = None + ) -> str: + """ + Generates a shared access signature for the file. + Use the returned signature with the sas_token parameter of FileService. + + :param str share_name: + Name of share. + :param Optional[str] directory_name: + Name of directory. SAS tokens cannot be created for directories, so + this parameter should only be present if file_name is provided. + :param Optional[str] file_name: + Name of file. + :param permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + Permissions must be ordered rcwd. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has been + specified in an associated stored access policy. + :type permission: str or FileSasPermissions or None + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: ~datetime.datetime or str or None + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. The provided datetime will always + be interpreted as UTC. + :type start: ~datetime.datetime or str or None + :param Optional[str] policy_id: + A unique value up to 64 characters in length that correlates to a + stored access policy. To create a stored access policy, use + set_file_service_properties. + :param Optional[str] ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS + restricts the request to those IP addresses. + :param Optional[str] protocol: + Specifies the protocol permitted for a request made. The default value + is https,http. See :class:`~azure.storage.common.models.Protocol` for possible values. + :param Optional[str] cache_control: + Response header value for Cache-Control when resource is accessed + using this shared access signature. + :param Optional[str] content_disposition: + Response header value for Content-Disposition when resource is accessed + using this shared access signature. + :param Optional[str] content_encoding: + Response header value for Content-Encoding when resource is accessed + using this shared access signature. + :param Optional[str] content_language: + Response header value for Content-Language when resource is accessed + using this shared access signature. + :param Optional[str] content_type: + Response header value for Content-Type when resource is accessed + using this shared access signature. + :param sts_hook: + For debugging purposes only. If provided, the hook is called with the string to sign + that was used to generate the SAS. + :type sts_hook: Optional[Callable[[str], None]] + :returns: The generated SAS token for the account. + :rtype: str + """ + resource_path = share_name + if directory_name is not None: + resource_path += '/' + str(directory_name) + if file_name is not None: + resource_path += '/' + str(file_name) + + sas = _FileSharedAccessHelper() + sas.add_base(permission, expiry, start, ip, protocol, self.x_ms_version) + sas.add_id(policy_id) + sas.add_resource('f') + sas.add_override_response_headers(cache_control, content_disposition, + content_encoding, content_language, + content_type) + sas.add_resource_signature(self.account_name, self.account_key, resource_path) + + if sts_hook is not None: + sts_hook(sas.string_to_sign) + + return sas.get_token() + + def generate_share( + self, share_name: str, + permission: Optional[Union["ShareSasPermissions", str]] = None, + expiry: Optional[Union["datetime", str]] = None, + start: Optional[Union["datetime", str]] = None, + policy_id: Optional[str] = None, + ip: Optional[str] = None, + protocol: Optional[str] = None, + cache_control: Optional[str] = None, + content_disposition: Optional[str] = None, + content_encoding: Optional[str] = None, + content_language: Optional[str] = None, + content_type: Optional[str] = None, + sts_hook: Optional[Callable[[str], None]] = None, + ) -> str: + ''' + Generates a shared access signature for the share. + Use the returned signature with the sas_token parameter of FileService. + + :param str share_name: + Name of share. + :param permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + Permissions must be ordered rcwdl. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has been + specified in an associated stored access policy. + :type permission: ~azure.storage.fileshare.ShareSasPermissions or str or None + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: ~datetime.datetime or str or None + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. The provided datetime will always + be interpreted as UTC. + :type start: ~datetime.datetime or str or None + :param Optional[str] policy_id: + A unique value up to 64 characters in length that correlates to a + stored access policy. To create a stored access policy, use + set_file_service_properties. + :param Optional[str] ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS + restricts the request to those IP addresses. + :param Optional[str] protocol: + Specifies the protocol permitted for a request made. The default value + is https,http. See :class:`~azure.storage.common.models.Protocol` for possible values. + :param Optional[str] cache_control: + Response header value for Cache-Control when resource is accessed + using this shared access signature. + :param Optional[str] content_disposition: + Response header value for Content-Disposition when resource is accessed + using this shared access signature. + :param Optional[str] content_encoding: + Response header value for Content-Encoding when resource is accessed + using this shared access signature. + :param Optional[str] content_language: + Response header value for Content-Language when resource is accessed + using this shared access signature. + :param Optional[str] content_type: + Response header value for Content-Type when resource is accessed + using this shared access signature. + :param sts_hook: + For debugging purposes only. If provided, the hook is called with the string to sign + that was used to generate the SAS. + :type sts_hook: Optional[Callable[[str], None]] + :returns: The generated SAS token for the account. + :rtype: str + ''' + sas = _FileSharedAccessHelper() + sas.add_base(permission, expiry, start, ip, protocol, self.x_ms_version) + sas.add_id(policy_id) + sas.add_resource('s') + sas.add_override_response_headers(cache_control, content_disposition, + content_encoding, content_language, + content_type) + sas.add_resource_signature(self.account_name, self.account_key, share_name) + + if sts_hook is not None: + sts_hook(sas.string_to_sign) + + return sas.get_token() + + +class _FileSharedAccessHelper(_SharedAccessHelper): + + def add_resource_signature(self, account_name, account_key, path): + def get_value_to_append(query): + return_value = self.query_dict.get(query) or '' + return return_value + '\n' + + if path[0] != '/': + path = '/' + path + + canonicalized_resource = '/file/' + account_name + path + '\n' + + # Form the string to sign from shared_access_policy and canonicalized + # resource. The order of values is important. + string_to_sign = \ + (get_value_to_append(QueryStringConstants.SIGNED_PERMISSION) + + get_value_to_append(QueryStringConstants.SIGNED_START) + + get_value_to_append(QueryStringConstants.SIGNED_EXPIRY) + + canonicalized_resource + + get_value_to_append(QueryStringConstants.SIGNED_IDENTIFIER) + + get_value_to_append(QueryStringConstants.SIGNED_IP) + + get_value_to_append(QueryStringConstants.SIGNED_PROTOCOL) + + get_value_to_append(QueryStringConstants.SIGNED_VERSION) + + get_value_to_append(QueryStringConstants.SIGNED_CACHE_CONTROL) + + get_value_to_append(QueryStringConstants.SIGNED_CONTENT_DISPOSITION) + + get_value_to_append(QueryStringConstants.SIGNED_CONTENT_ENCODING) + + get_value_to_append(QueryStringConstants.SIGNED_CONTENT_LANGUAGE) + + get_value_to_append(QueryStringConstants.SIGNED_CONTENT_TYPE)) + + # remove the trailing newline + if string_to_sign[-1] == '\n': + string_to_sign = string_to_sign[:-1] + + self._add_query(QueryStringConstants.SIGNED_SIGNATURE, + sign_string(account_key, string_to_sign)) + self.string_to_sign = string_to_sign + + +def generate_account_sas( + account_name: str, + account_key: str, + resource_types: Union["ResourceTypes", str], + permission: Union["AccountSasPermissions", str], + expiry: Union["datetime", str], + start: Optional[Union["datetime", str]] = None, + ip: Optional[str] = None, + *, + services: Union[Services, str] = Services(fileshare=True), + sts_hook: Optional[Callable[[str], None]] = None, + **kwargs: Any +) -> str: + """Generates a shared access signature for the file service. + + Use the returned signature with the credential parameter of any ShareServiceClient, + ShareClient, ShareDirectoryClient, or ShareFileClient. + + :param str account_name: + The storage account name used to generate the shared access signature. + :param str account_key: + The account key, also called shared key or access key, to generate the shared access signature. + :param resource_types: + Specifies the resource types that are accessible with the account SAS. + :type resource_types: ~azure.storage.fileshare.ResourceTypes or str + :param permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + :type permission: ~azure.storage.fileshare.AccountSasPermissions or str + :param expiry: + The time at which the shared access signature becomes invalid. + The provided datetime will always be interpreted as UTC. + :type expiry: ~datetime.datetime or str + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. The provided datetime will always + be interpreted as UTC. + :type start: ~datetime.datetime or str or None + :param str ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS + restricts the request to those IP addresses. + :keyword Union[Services, str] services: + Specifies the services that the Shared Access Signature (sas) token will be able to be utilized with. + Will default to only this package (i.e. fileshare) if not provided. + :keyword str protocol: + Specifies the protocol permitted for a request made. The default value is https. + :keyword sts_hook: + For debugging purposes only. If provided, the hook is called with the string to sign + that was used to generate the SAS. + :paramtype sts_hook: Optional[Callable[[str], None]] + :return: A Shared Access Signature (sas) token. + :rtype: str + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_authentication.py + :start-after: [START generate_sas_token] + :end-before: [END generate_sas_token] + :language: python + :dedent: 8 + :caption: Generate a sas token. + """ + sas = SharedAccessSignature(account_name, account_key) + return sas.generate_account( + services=services, + resource_types=resource_types, + permission=permission, + expiry=expiry, + start=start, + ip=ip, + sts_hook=sts_hook, + **kwargs + ) + + +def generate_share_sas( + account_name: str, + share_name: str, + account_key: str, + permission: Optional[Union["ShareSasPermissions", str]] = None, + expiry: Optional[Union["datetime", str]] = None, + start: Optional[Union["datetime", str]] = None, + policy_id: Optional[str] = None, + ip: Optional[str] = None, + *, + sts_hook: Optional[Callable[[str], None]] = None, + **kwargs: Any +) -> str: + """Generates a shared access signature for a share. + + Use the returned signature with the credential parameter of any ShareServiceClient, + ShareClient, ShareDirectoryClient, or ShareFileClient. + + :param str account_name: + The storage account name used to generate the shared access signature. + :param str share_name: + The name of the share. + :param str account_key: + The account key, also called shared key or access key, to generate the shared access signature. + :param permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + Permissions must be ordered rcwdl. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has been + specified in an associated stored access policy. + :type permission: ~azure.storage.fileshare.ShareSasPermissions or str or None + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: ~datetime.datetime or str or None + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. The provided datetime will always + be interpreted as UTC. + :type start: ~datetime.datetime or str or None + :param Optional[str] policy_id: + A unique value up to 64 characters in length that correlates to a + stored access policy. To create a stored access policy, use + :func:`~azure.storage.fileshare.ShareClient.set_share_access_policy`. + :param Optional[str] ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS + restricts the request to those IP addresses. + :keyword str cache_control: + Response header value for Cache-Control when resource is accessed + using this shared access signature. + :keyword str content_disposition: + Response header value for Content-Disposition when resource is accessed + using this shared access signature. + :keyword str content_encoding: + Response header value for Content-Encoding when resource is accessed + using this shared access signature. + :keyword str content_language: + Response header value for Content-Language when resource is accessed + using this shared access signature. + :keyword str content_type: + Response header value for Content-Type when resource is accessed + using this shared access signature. + :keyword str protocol: + Specifies the protocol permitted for a request made. The default value is https. + :keyword sts_hook: + For debugging purposes only. If provided, the hook is called with the string to sign + that was used to generate the SAS. + :paramtype sts_hook: Optional[Callable[[str], None]] + :return: A Shared Access Signature (sas) token. + :rtype: str + """ + if not policy_id: + if not expiry: + raise ValueError("'expiry' parameter must be provided when not using a stored access policy.") + if not permission: + raise ValueError("'permission' parameter must be provided when not using a stored access policy.") + sas = FileSharedAccessSignature(account_name, account_key) + return sas.generate_share( + share_name=share_name, + permission=permission, + expiry=expiry, + start=start, + policy_id=policy_id, + ip=ip, + sts_hook=sts_hook, + **kwargs + ) + + +def generate_file_sas( + account_name: str, + share_name: str, + file_path: List[str], + account_key: str, + permission: Optional[Union["FileSasPermissions", str]] = None, + expiry: Optional[Union["datetime", str]] = None, + start: Optional[Union["datetime", str]] = None, + policy_id: Optional[str] = None, + ip: Optional[str] = None, + *, + sts_hook: Optional[Callable[[str], None]] = None, + **kwargs: Any +) -> str: + """Generates a shared access signature for a file. + + Use the returned signature with the credential parameter of any ShareServiceClient, + ShareClient, ShareDirectoryClient, or ShareFileClient. + + :param str account_name: + The storage account name used to generate the shared access signature. + :param str share_name: + The name of the share. + :param file_path: + The file path represented as a list of path segments, including the file name. + :type file_path: List[str] + :param str account_key: + The account key, also called shared key or access key, to generate the shared access signature. + :param permission: + The permissions associated with the shared access signature. The + user is restricted to operations allowed by the permissions. + Permissions must be ordered rcwd. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has been + specified in an associated stored access policy. + :type permission: ~azure.storage.fileshare.FileSasPermissions or str or None + :param expiry: + The time at which the shared access signature becomes invalid. + Required unless an id is given referencing a stored access policy + which contains this field. This field must be omitted if it has + been specified in an associated stored access policy. Azure will always + convert values to UTC. If a date is passed in without timezone info, it + is assumed to be UTC. + :type expiry: ~datetime.datetime or str or None + :param start: + The time at which the shared access signature becomes valid. If + omitted, start time for this call is assumed to be the time when the + storage service receives the request. The provided datetime will always + be interpreted as UTC. + :type start: ~datetime.datetime or str or None + :param Optional[str] policy_id: + A unique value up to 64 characters in length that correlates to a + stored access policy. + :param Optional[str] ip: + Specifies an IP address or a range of IP addresses from which to accept requests. + If the IP address from which the request originates does not match the IP address + or address range specified on the SAS token, the request is not authenticated. + For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS + restricts the request to those IP addresses. + :keyword str cache_control: + Response header value for Cache-Control when resource is accessed + using this shared access signature. + :keyword str content_disposition: + Response header value for Content-Disposition when resource is accessed + using this shared access signature. + :keyword str content_encoding: + Response header value for Content-Encoding when resource is accessed + using this shared access signature. + :keyword str content_language: + Response header value for Content-Language when resource is accessed + using this shared access signature. + :keyword str content_type: + Response header value for Content-Type when resource is accessed + using this shared access signature. + :keyword str protocol: + Specifies the protocol permitted for a request made. The default value is https. + :keyword sts_hook: + For debugging purposes only. If provided, the hook is called with the string to sign + that was used to generate the SAS. + :paramtype sts_hook: Optional[Callable[[str], None]] + :return: A Shared Access Signature (sas) token. + :rtype: str + """ + if not policy_id: + if not expiry: + raise ValueError("'expiry' parameter must be provided when not using a stored access policy.") + if not permission: + raise ValueError("'permission' parameter must be provided when not using a stored access policy.") + sas = FileSharedAccessSignature(account_name, account_key) + if len(file_path) > 1: + dir_path = '/'.join(file_path[:-1]) + else: + dir_path = None + return sas.generate_file( + share_name=share_name, + directory_name=dir_path, + file_name=file_path[-1], + permission=permission, + expiry=expiry, + start=start, + policy_id=policy_id, + ip=ip, + sts_hook=sts_hook, + **kwargs + ) + + +def _is_credential_sastoken(credential: Any) -> bool: + if not credential or not isinstance(credential, str): + return False + + sas_values = QueryStringConstants.to_list() + parsed_query = parse_qs(credential.lstrip("?")) + if parsed_query and all(k in sas_values for k in parsed_query): + return True + return False diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_version.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_version.py new file mode 100644 index 00000000..79adcbe3 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/_version.py @@ -0,0 +1,7 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +VERSION = "12.21.0" diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/__init__.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/__init__.py new file mode 100644 index 00000000..73393b81 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/__init__.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- + +from ._file_client_async import ShareFileClient +from ._directory_client_async import ShareDirectoryClient +from ._share_client_async import ShareClient +from ._share_service_client_async import ShareServiceClient +from ._lease_async import ShareLeaseClient + + +__all__ = [ + 'ShareFileClient', + 'ShareDirectoryClient', + 'ShareClient', + 'ShareServiceClient', + 'ShareLeaseClient', +] diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_directory_client_async.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_directory_client_async.py new file mode 100644 index 00000000..8673362c --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_directory_client_async.py @@ -0,0 +1,988 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=docstring-keyword-should-match-keyword-only + +import functools +import sys +import time +import warnings +from datetime import datetime +from typing import ( + Any, AnyStr, AsyncIterable, cast, Dict, IO, Iterable, Optional, Union, + TYPE_CHECKING +) +from typing_extensions import Self + +from azure.core.async_paging import AsyncItemPaged +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.core.pipeline import AsyncPipeline +from azure.core.tracing.decorator import distributed_trace +from azure.core.tracing.decorator_async import distributed_trace_async +from .._deserialize import deserialize_directory_properties +from .._directory_client_helpers import ( + _format_url, + _from_directory_url, + _parse_url +) +from .._generated.aio import AzureFileStorage +from .._parser import _datetime_to_str, _get_file_permission, _parse_snapshot +from .._serialize import get_api_version, get_dest_access_conditions, get_rename_smb_properties +from .._shared.base_client import parse_query, StorageAccountHostsMixin +from .._shared.base_client_async import parse_connection_str, AsyncStorageAccountHostsMixin, AsyncTransportWrapper +from .._shared.policies_async import ExponentialRetry +from .._shared.request_handlers import add_metadata_headers +from .._shared.response_handlers import process_storage_error, return_response_headers +from ._file_client_async import ShareFileClient +from ._models import DirectoryPropertiesPaged, Handle, HandlesPaged + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + +if TYPE_CHECKING: + from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential + from azure.core.credentials_async import AsyncTokenCredential + from .._models import DirectoryProperties, FileProperties, NTFSAttributes + + +class ShareDirectoryClient(AsyncStorageAccountHostsMixin, StorageAccountHostsMixin): # type: ignore [misc] + """A client to interact with a specific directory, although it may not yet exist. + + For operations relating to a specific subdirectory or file in this share, the clients for those + entities can also be retrieved using the :func:`get_subdirectory_client` and :func:`get_file_client` functions. + + :param str account_url: + The URI to the storage account. In order to create a client given the full URI to the directory, + use the :func:`from_directory_url` classmethod. + :param share_name: + The name of the share for the directory. + :type share_name: str + :param str directory_path: + The directory path for the directory with which to interact. + If specified, this value will override a directory value specified in the directory URL. + :param str snapshot: + An optional share snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`ShareClient.create_snapshot`. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of an AsyncTokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials_async.AsyncTokenCredential or + str or dict[str, str] or None + :keyword token_intent: + Required when using `AsyncTokenCredential` for authentication and ignored for other forms of authentication. + Specifies the intent for all requests when using `AsyncTokenCredential` authentication. Possible values are: + + backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory + ACLs are bypassed and full permissions are granted. User must also have required RBAC permission. + + :paramtype token_intent: Literal['backup'] + :keyword bool allow_trailing_dot: If true, the trailing dot will not be trimmed from the target URI. + :keyword bool allow_source_trailing_dot: If true, the trailing dot will not be trimmed from the source URI. + :keyword str api_version: + The Storage API version to use for requests. Default value is the most recent service version that is + compatible with the current SDK. Setting to an older version may result in reduced feature compatibility. + + .. versionadded:: 12.1.0 + + :keyword str secondary_hostname: + The hostname of the secondary endpoint. + :keyword int max_range_size: The maximum range size used for a file upload. Defaults to 4*1024*1024. + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type AsyncTokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.file.core.windows.net. + """ + def __init__( + self, account_url: str, + share_name: str, + directory_path: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long + *, + token_intent: Optional[Literal['backup']] = None, + **kwargs: Any + ) -> None: + kwargs['retry_policy'] = kwargs.get('retry_policy') or ExponentialRetry(**kwargs) + loop = kwargs.pop('loop', None) + if loop and sys.version_info >= (3, 8): + warnings.warn("The 'loop' parameter was deprecated from asyncio's high-level" + "APIs in Python 3.8 and is no longer supported.", DeprecationWarning) + if hasattr(credential, 'get_token') and not token_intent: + raise ValueError("'token_intent' keyword is required when 'credential' is an AsyncTokenCredential.") + parsed_url = _parse_url(account_url, share_name) + path_snapshot, sas_token = parse_query(parsed_url.query) + if not sas_token and not credential: + raise ValueError( + 'You need to provide either an account shared key or SAS token when creating a storage service.') + self.snapshot = _parse_snapshot(snapshot, path_snapshot) + self.share_name = share_name + self.directory_path = directory_path + + self._query_str, credential = self._format_query_string( + sas_token, credential, share_snapshot=self.snapshot) + super(ShareDirectoryClient, self).__init__( + parsed_url, service='file-share', credential=credential, **kwargs) + self.allow_trailing_dot = kwargs.pop('allow_trailing_dot', None) + self.allow_source_trailing_dot = kwargs.pop('allow_source_trailing_dot', None) + self.file_request_intent = token_intent + self._client = AzureFileStorage(url=self.url, base_url=self.url, pipeline=self._pipeline, + allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, + file_request_intent=self.file_request_intent) + self._client._config.version = get_api_version(kwargs) # type: ignore [assignment] + + @classmethod + def from_directory_url( + cls, directory_url: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """Create a ShareDirectoryClient from a directory url. + + :param str directory_url: + The full URI to the directory. + :param str snapshot: + An optional share snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`ShareClient.create_snapshot`. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a AsyncTokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials_async.AsyncTokenCredential or + str or dict[str, str] or None + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory authentication. + Only has an effect when credential is of type AsyncTokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.file.core.windows.net. + :returns: A directory client. + :rtype: ~azure.storage.fileshare.ShareDirectoryClient + """ + account_url, share_name, directory_path, snapshot = _from_directory_url(directory_url, snapshot) + return cls( + account_url=account_url, share_name=share_name, directory_path=directory_path, + snapshot=snapshot, credential=credential, **kwargs) + + def _format_url(self, hostname: str) -> str: + """Format the endpoint URL according to the current location mode hostname. + + :param str hostname: + The hostname of the current location mode. + :returns: A formatted endpoint URL including the current location mode hostname. + :rtype: str + """ + return _format_url(self.scheme, hostname, self.share_name, self.directory_path, self._query_str) + + @classmethod + def from_connection_string( + cls, conn_str: str, + share_name: str, + directory_path: str, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """Create ShareDirectoryClient from a Connection String. + + :param str conn_str: + A connection string to an Azure Storage account. + :param share_name: The name of the share. + :type share_name: str + :param str directory_path: + The directory path. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of an AsyncTokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + Optional[Union[str, dict[str, str], AzureNamedKeyCredential, AzureSasCredential, "AsyncTokenCredential"]] + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory authentication. + Only has an effect when credential is of type AsyncTokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.file.core.windows.net. + :returns: A directory client. + :rtype: ~azure.storage.fileshare.aio.ShareDirectoryClient + """ + account_url, secondary, credential = parse_connection_str(conn_str, credential, 'file') + if 'secondary_hostname' not in kwargs: + kwargs['secondary_hostname'] = secondary + return cls( + account_url, share_name=share_name, directory_path=directory_path, credential=credential, **kwargs) + + def get_file_client(self, file_name: str, **kwargs: Any) -> ShareFileClient: + """Get a client to interact with a specific file. + + The file need not already exist. + + :param str file_name: + The name of the file. + :returns: A File Client. + :rtype: ~azure.storage.fileshare.ShareFileClient + """ + if self.directory_path: + file_name = self.directory_path.rstrip('/') + "/" + file_name + + _pipeline = AsyncPipeline( + transport=AsyncTransportWrapper(self._pipeline._transport), # pylint: disable=protected-access + policies=self._pipeline._impl_policies # type: ignore [arg-type] # pylint: disable=protected-access + ) + return ShareFileClient( + self.url, file_path=file_name, share_name=self.share_name, snapshot=self.snapshot, + credential=self.credential, api_version=self.api_version, _hosts=self._hosts, _configuration=self._config, + _pipeline=_pipeline, _location_mode=self._location_mode, allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, token_intent=self.file_request_intent, + **kwargs) + + def get_subdirectory_client(self, directory_name: str, **kwargs) -> "ShareDirectoryClient": + """Get a client to interact with a specific subdirectory. + + The subdirectory need not already exist. + + :param str directory_name: + The name of the subdirectory. + :returns: A Directory Client. + :rtype: ~azure.storage.fileshare.aio.ShareDirectoryClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory_async.py + :start-after: [START get_subdirectory_client] + :end-before: [END get_subdirectory_client] + :language: python + :dedent: 16 + :caption: Gets the subdirectory client. + """ + directory_path = directory_name + if self.directory_path: + directory_path = self.directory_path.rstrip('/') + "/" + directory_name + + _pipeline = AsyncPipeline( + transport=AsyncTransportWrapper(self._pipeline._transport), # pylint: disable=protected-access + policies=self._pipeline._impl_policies # type: ignore [arg-type] # pylint: disable=protected-access + ) + return ShareDirectoryClient( + self.url, share_name=self.share_name, directory_path=directory_path, snapshot=self.snapshot, + credential=self.credential, api_version=self.api_version, _hosts=self._hosts, _configuration=self._config, + _pipeline=_pipeline, _location_mode=self._location_mode, allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, token_intent=self.file_request_intent, + **kwargs) + + @distributed_trace_async + async def create_directory(self, **kwargs: Any) -> Dict[str, Any]: + """Creates a new directory under the directory referenced by the client. + + :keyword file_attributes: + The file system attributes for files and directories. + If not set, the default value would be "none" and the attributes will be set to "Archive". + Here is an example for when the var type is str: 'Temporary|Archive'. + file_attributes value is not case sensitive. + :paramtype file_attributes: str or ~azure.storage.fileshare.NTFSAttributes or None + :keyword file_creation_time: Creation time for the directory. + :paramtype file_creation_time: str or ~datetime.datetime or None + :keyword file_last_write_time: Last write time for the directory. + :paramtype file_last_write_time: str or ~datetime.datetime or None + :keyword str file_permission: + If specified the permission (security descriptor) shall be set + for the directory/file. This header can be used if Permission size is + <= 8KB, else file-permission-key header shall be used. + Default value: Inherit. If SDDL is specified as input, it must have owner, group and dacl. + Note: Only one of the file-permission or file-permission-key should be specified. + :keyword str file_permission_key: + Key of the permission to be set for the directory/file. + Note: Only one of the file-permission or file-permission-key should be specified. + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_change_time: + Change time for the directory. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword metadata: + Name-value pairs associated with the directory as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword str owner: + NFS only. The owner of the directory. + :keyword str group: + NFS only. The owning group of the directory. + :keyword str file_mode: + NFS only. The file mode of the directory. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: Directory-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory_async.py + :start-after: [START create_directory] + :end-before: [END create_directory] + :language: python + :dedent: 16 + :caption: Creates a directory. + """ + metadata = kwargs.pop('metadata', None) + timeout = kwargs.pop('timeout', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + + file_attributes = kwargs.pop('file_attributes', None) + file_creation_time = kwargs.pop('file_creation_time', None) + file_last_write_time = kwargs.pop('file_last_write_time', None) + file_change_time = kwargs.pop('file_change_time', None) + file_permission = kwargs.pop('file_permission', None) + file_permission_key = kwargs.pop('file_permission_key', None) + file_permission = _get_file_permission(file_permission, file_permission_key, None) + + try: + return cast(Dict[str, Any], await self._client.directory.create( + file_attributes=str(file_attributes) if file_attributes is not None else file_attributes, + file_creation_time=_datetime_to_str(file_creation_time), + file_last_write_time=_datetime_to_str(file_last_write_time), + file_change_time=_datetime_to_str(file_change_time), + file_permission=file_permission, + file_permission_key=file_permission_key, + timeout=timeout, + cls=return_response_headers, + headers=headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def delete_directory(self, **kwargs: Any) -> None: + """Marks the directory for deletion. The directory is + later deleted during garbage collection. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory_async.py + :start-after: [START delete_directory] + :end-before: [END delete_directory] + :language: python + :dedent: 16 + :caption: Deletes a directory. + """ + timeout = kwargs.pop('timeout', None) + try: + await self._client.directory.delete(timeout=timeout, **kwargs) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def rename_directory(self, new_name: str, **kwargs: Any) -> "ShareDirectoryClient": + """ + Rename the source directory. + + :param str new_name: + The new directory name. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword bool overwrite: + A boolean value for if the destination file already exists, whether this request will + overwrite the file or not. If true, the rename will succeed and will overwrite the + destination file. If not provided or if false and the destination file does exist, the + request will not overwrite the destination file. If provided and the destination file + doesn't exist, the rename will succeed. + :keyword bool ignore_read_only: + A boolean value that specifies whether the ReadOnly attribute on a preexisting destination + file should be respected. If true, the rename will succeed, otherwise, a previous file at the + destination with the ReadOnly attribute set will cause the rename to fail. + :keyword str file_permission: + If specified the permission (security descriptor) shall be set for the directory. This header + can be used if Permission size is <= 8KB, else file_permission_key shall be used. + If SDDL is specified as input, it must have owner, group and dacl. + A value of 'preserve' can be passed to preserve source permissions. + Note: Only one of the file_permission or file_permission_key should be specified. + :keyword str file_permission_key: + Key of the permission to be set for the directory. + Note: Only one of the file-permission or file-permission-key should be specified. + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_attributes: + The file system attributes for the directory. + :paramtype file_attributes: ~azure.storage.fileshare.NTFSAttributes or str + :keyword file_creation_time: + Creation time for the directory. + :paramtype file_creation_time: ~datetime.datetime or str + :keyword file_last_write_time: + Last write time for the file. + :paramtype file_last_write_time: ~datetime.datetime or str + :keyword file_change_time: + Change time for the directory. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword Dict[str,str] metadata: + A name-value pair to associate with a file storage object. + :keyword destination_lease: + Required if the destination file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + :paramtype destination_lease: ~azure.storage.fileshare.ShareLeaseClient or str + :returns: The new Directory Client. + :rtype: ~azure.storage.fileshare.ShareDirectoryClient + """ + if not new_name: + raise ValueError("Please specify a new directory name.") + + new_name = new_name.strip('/') + new_path_and_query = new_name.split('?') + new_dir_path = new_path_and_query[0] + if len(new_path_and_query) == 2: + new_dir_sas = new_path_and_query[1] or self._query_str.strip('?') + else: + new_dir_sas = self._query_str.strip('?') + + new_directory_client = ShareDirectoryClient( + f'{self.scheme}://{self.primary_hostname}', self.share_name, new_dir_path, + credential=new_dir_sas or self.credential, api_version=self.api_version, + _hosts=self._hosts, _configuration=self._config, _pipeline=self._pipeline, + _location_mode=self._location_mode, allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, token_intent=self.file_request_intent + ) + + kwargs.update(get_rename_smb_properties(kwargs)) + + timeout = kwargs.pop('timeout', None) + overwrite = kwargs.pop('overwrite', None) + metadata = kwargs.pop('metadata', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + + destination_access_conditions = get_dest_access_conditions(kwargs.pop('destination_lease', None)) + + try: + await new_directory_client._client.directory.rename( # pylint: disable=protected-access + self.url, + timeout=timeout, + replace_if_exists=overwrite, + destination_lease_access_conditions=destination_access_conditions, + headers=headers, + **kwargs) + + return new_directory_client + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def list_directories_and_files( + self, + name_starts_with: Optional[str] = None, + **kwargs: Any + ) -> AsyncItemPaged[Union["DirectoryProperties", "FileProperties"]]: + """Lists all the directories and files under the directory. + + :param str name_starts_with: + Filters the results to return only entities whose names + begin with the specified prefix. + :keyword List[str] include: + Include this parameter to specify one or more datasets to include in the response. + Possible str values are "timestamps", "Etag", "Attributes", "PermissionKey". + + .. versionadded:: 12.6.0 + + This keyword argument was introduced in API version '2020-10-02'. + + :keyword bool include_extended_info: + If this is set to true, file id will be returned in listed results. + + .. versionadded:: 12.6.0 + + This keyword argument was introduced in API version '2020-10-02'. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: An auto-paging iterable of dict-like DirectoryProperties and FileProperties + :rtype: ~azure.core.paging.ItemPaged[Union[DirectoryProperties, FileProperties]] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory_async.py + :start-after: [START lists_directory] + :end-before: [END lists_directory] + :language: python + :dedent: 16 + :caption: List directories and files. + """ + timeout = kwargs.pop('timeout', None) + results_per_page = kwargs.pop('results_per_page', None) + command = functools.partial( + self._client.directory.list_files_and_directories_segment, + sharesnapshot=self.snapshot, + timeout=timeout, + **kwargs) + return AsyncItemPaged( + command, prefix=name_starts_with, results_per_page=results_per_page, + page_iterator_class=DirectoryPropertiesPaged) + + @distributed_trace + def list_handles(self, recursive: bool = False, **kwargs: Any) -> AsyncItemPaged["Handle"]: + """Lists opened handles on a directory or a file under the directory. + + :param bool recursive: + Boolean that specifies if operation should apply to the directory specified by the client, + its files, its subdirectories and their files. Default value is False. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: An auto-paging iterable of Handle + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.storage.fileshare.Handle] + """ + timeout = kwargs.pop('timeout', None) + results_per_page = kwargs.pop('results_per_page', None) + command = functools.partial( + self._client.directory.list_handles, + sharesnapshot=self.snapshot, + timeout=timeout, + recursive=recursive, + **kwargs) + return AsyncItemPaged( + command, results_per_page=results_per_page, + page_iterator_class=HandlesPaged) + + @distributed_trace_async + async def exists(self, **kwargs: Any) -> bool: + """ + Returns True if a directory exists and returns False otherwise. + + :kwarg int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: True if the directory exists, False otherwise. + :rtype: bool + """ + try: + await self._client.directory.get_properties(**kwargs) + return True + except HttpResponseError as error: + try: + process_storage_error(error) + except ResourceNotFoundError: + return False + + @distributed_trace_async + async def close_handle(self, handle: Union[str, "Handle"], **kwargs: Any) -> Dict[str, int]: + """Close an open file handle. + + :param handle: + A specific handle to close. + :type handle: str or ~azure.storage.fileshare.Handle + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: The number of handles closed (this may be 0 if the specified handle was not found) + and the number of handles failed to close in a dict. + :rtype: dict[str, int] + """ + if isinstance(handle, Handle): + handle_id = handle.id + else: + handle_id = handle + if handle_id == '*': + raise ValueError("Handle ID '*' is not supported. Use 'close_all_handles' instead.") + try: + response = await self._client.directory.force_close_handles( + handle_id, + marker=None, + recursive=None, + sharesnapshot=self.snapshot, + cls=return_response_headers, + **kwargs + ) + return { + 'closed_handles_count': response.get('number_of_handles_closed', 0), + 'failed_handles_count': response.get('number_of_handles_failed', 0) + } + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def close_all_handles(self, recursive: bool = False, **kwargs: Any) -> Dict[str, int]: + """Close any open file handles. + + This operation will block until the service has closed all open handles. + + :param bool recursive: + Boolean that specifies if operation should apply to the directory specified by the client, + its files, its subdirectories and their files. Default value is False. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: The number of handles closed (this may be 0 if the specified handle was not found) + and the number of handles failed to close in a dict. + :rtype: dict[str, int] + """ + timeout = kwargs.pop('timeout', None) + start_time = time.time() + + try_close = True + continuation_token = None + total_closed = 0 + total_failed = 0 + while try_close: + try: + response = await self._client.directory.force_close_handles( + handle_id='*', + timeout=timeout, + marker=continuation_token, + recursive=recursive, + sharesnapshot=self.snapshot, + cls=return_response_headers, + **kwargs + ) + except HttpResponseError as error: + process_storage_error(error) + continuation_token = response.get('marker') + try_close = bool(continuation_token) + total_closed += response.get('number_of_handles_closed', 0) + total_failed += response.get('number_of_handles_failed', 0) + if timeout: + timeout = max(0, timeout - (time.time() - start_time)) + return { + 'closed_handles_count': total_closed, + 'failed_handles_count': total_failed + } + + @distributed_trace_async + async def get_directory_properties(self, **kwargs: Any) -> "DirectoryProperties": + """Returns all user-defined metadata and system properties for the + specified directory. The data returned does not include the directory's + list of files. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: DirectoryProperties + :rtype: ~azure.storage.fileshare.DirectoryProperties + """ + timeout = kwargs.pop('timeout', None) + try: + response = cast("DirectoryProperties", await self._client.directory.get_properties( + timeout=timeout, + cls=deserialize_directory_properties, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + return response + + @distributed_trace_async + async def set_directory_metadata(self, metadata: Dict[str, Any], **kwargs: Any) -> Dict[str, Any]: + """Sets the metadata for the directory. + + Each call to this operation replaces all existing metadata + attached to the directory. To remove all metadata from the directory, + call this operation with an empty metadata dict. + + :param metadata: + Name-value pairs associated with the directory as metadata. + :type metadata: dict[str, str] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: Directory-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + """ + timeout = kwargs.pop('timeout', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + try: + return cast(Dict[str, Any], await self._client.directory.set_metadata( + timeout=timeout, + cls=return_response_headers, + headers=headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def set_http_headers( + self, file_attributes: Optional[Union[str, "NTFSAttributes"]] = None, + file_creation_time: Optional[Union[str, datetime]] = None, + file_last_write_time: Optional[Union[str, datetime]] = None, + file_permission: Optional[str] = None, + permission_key: Optional[str] = None, + **kwargs: Any + ) -> Dict[str, Any]: + """Sets HTTP headers on the directory. + + :param file_attributes: + The file system attributes for files and directories. + If not set, indicates preservation of existing values. + Here is an example for when the var type is str: 'Temporary|Archive' + :type file_attributes: str or ~azure.storage.fileshare.NTFSAttributes or None + :param file_creation_time: Creation time for the file + :type file_creation_time: str or ~datetime.datetime or None + :param file_last_write_time: Last write time for the file + :type file_last_write_time: str or ~datetime.datetime or None + :param file_permission: If specified the permission (security + descriptor) shall be set for the directory/file. This header can be + used if Permission size is <= 8KB, else x-ms-file-permission-key + header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the + x-ms-file-permission or x-ms-file-permission-key should be specified. + :type file_permission: str + :param permission_key: Key of the permission to be set for the + directory/file. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. + :type permission_key: str + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_change_time: + Change time for the directory. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword str owner: + NFS only. The owner of the directory. + :keyword str group: + NFS only. The owning group of the directory. + :keyword str file_mode: + NFS only. The file mode of the directory. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + """ + timeout = kwargs.pop('timeout', None) + file_permission = _get_file_permission(file_permission, permission_key, None) + file_change_time = kwargs.pop('file_change_time', None) + try: + return cast(Dict[str, Any], await self._client.directory.set_properties( + file_attributes=str(file_attributes) if file_attributes is not None else file_attributes, + file_creation_time=_datetime_to_str(file_creation_time), + file_last_write_time=_datetime_to_str(file_last_write_time), + file_change_time=_datetime_to_str(file_change_time), + file_permission=file_permission, + file_permission_key=permission_key, + timeout=timeout, + cls=return_response_headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def create_subdirectory(self, directory_name: str, **kwargs: Any) -> "ShareDirectoryClient": + """Creates a new subdirectory and returns a client to interact + with the subdirectory. + + :param str directory_name: + The name of the subdirectory. + :keyword metadata: + Name-value pairs associated with the subdirectory as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: ShareDirectoryClient + :rtype: ~azure.storage.fileshare.aio.ShareDirectoryClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory_async.py + :start-after: [START create_subdirectory] + :end-before: [END create_subdirectory] + :language: python + :dedent: 16 + :caption: Create a subdirectory. + """ + metadata = kwargs.pop('metadata', None) + timeout = kwargs.pop('timeout', None) + subdir = self.get_subdirectory_client(directory_name) + await subdir.create_directory(metadata=metadata, timeout=timeout, **kwargs) + return subdir + + @distributed_trace_async + async def delete_subdirectory(self, directory_name: str, **kwargs: Any) -> None: + """Deletes a subdirectory. + + :param str directory_name: + The name of the subdirectory. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory_async.py + :start-after: [START delete_subdirectory] + :end-before: [END delete_subdirectory] + :language: python + :dedent: 16 + :caption: Delete a subdirectory. + """ + timeout = kwargs.pop('timeout', None) + subdir = self.get_subdirectory_client(directory_name) + await subdir.delete_directory(timeout=timeout, **kwargs) + + @distributed_trace_async + async def upload_file( + self, file_name: str, + data: Union[bytes, str, Iterable[AnyStr], AsyncIterable[AnyStr], IO[AnyStr]], + length: Optional[int] = None, + **kwargs: Any + ) -> ShareFileClient: + """Creates a new file in the directory and returns a ShareFileClient + to interact with the file. + + :param str file_name: + The name of the file. + :param data: + Content of the file. + :type data: Union[bytes, str, Iterable[AnyStr], AsyncIterable[AnyStr], IO[AnyStr]] + :param int length: + Length of the file in bytes. Specify its maximum size, up to 1 TiB. + :keyword metadata: + Name-value pairs associated with the file as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword ~azure.storage.fileshare.ContentSettings content_settings: + ContentSettings object used to set file properties. Used to set content type, encoding, + language, disposition, md5, and cache control. + :keyword bool validate_content: + If true, calculates an MD5 hash for each range of the file. The storage + service checks the hash of the content that has arrived with the hash + that was sent. This is primarily valuable for detecting bitflips on + the wire if using http instead of https as https (the default) will + already validate. Note that this MD5 hash is not stored with the + file. + :keyword int max_concurrency: + Maximum number of parallel connections to use. + :keyword progress_hook: + An async callback to track the progress of a long running upload. The signature is + function(current: int, total: Optional[int]) where current is the number of bytes transferred + so far, and total is the size of the blob or None if the size is unknown. + :paramtype progress_hook: Callable[[int, Optional[int]], Awaitable[None]] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword str encoding: + Defaults to UTF-8. + :returns: ShareFileClient + :rtype: ~azure.storage.fileshare.aio.ShareFileClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory_async.py + :start-after: [START upload_file_to_directory] + :end-before: [END upload_file_to_directory] + :language: python + :dedent: 16 + :caption: Upload a file to a directory. + """ + file_client = self.get_file_client(file_name) + await file_client.upload_file( + data, + length=length, + **kwargs) + return file_client + + @distributed_trace_async + async def delete_file(self, file_name: str, **kwargs: Any) -> None: + """Marks the specified file for deletion. The file is later + deleted during garbage collection. + + :param str file_name: + The name of the file to delete. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_directory_async.py + :start-after: [START delete_file_in_directory] + :end-before: [END delete_file_in_directory] + :language: python + :dedent: 16 + :caption: Delete a file in a directory. + """ + file_client = self.get_file_client(file_name) + await file_client.delete_file(**kwargs) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_download_async.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_download_async.py new file mode 100644 index 00000000..278c5e01 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_download_async.py @@ -0,0 +1,502 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=invalid-overridden-method +# mypy: disable-error-code=override + +import asyncio +import sys +import warnings +from io import BytesIO +from itertools import islice +from typing import ( + Any, AsyncIterator, Awaitable, Callable, + cast, Generator, IO, Optional, Tuple, + TYPE_CHECKING +) + +from azure.core.exceptions import HttpResponseError, ResourceModifiedError +from .._download import _ChunkDownloader +from .._shared.request_handlers import validate_and_format_range_headers +from .._shared.response_handlers import parse_length_from_content_range, process_storage_error + +if TYPE_CHECKING: + from .._generated.aio.operations import FileOperations + from .._models import FileProperties + from .._shared.models import StorageConfiguration + + +async def process_content(data: Any) -> bytes: + if data is None: + raise ValueError("Response cannot be None.") + + try: + await data.response.load_body() + return cast(bytes, data.response.body()) + except Exception as error: + raise HttpResponseError(message="Download stream interrupted.", response=data.response, error=error) from error + + +class _AsyncChunkDownloader(_ChunkDownloader): + def __init__(self, **kwargs: Any) -> None: + super(_AsyncChunkDownloader, self).__init__(**kwargs) + self.stream_lock_async = asyncio.Lock() if kwargs.get('parallel') else None + self.progress_lock_async = asyncio.Lock() if kwargs.get('parallel') else None + + async def process_chunk(self, chunk_start: int) -> None: + chunk_start, chunk_end = self._calculate_range(chunk_start) + chunk_data = await self._download_chunk(chunk_start, chunk_end - 1) + length = chunk_end - chunk_start + if length > 0: + await self._write_to_stream(chunk_data, chunk_start) + await self._update_progress(length) + + async def yield_chunk(self, chunk_start: int) -> bytes: + chunk_start, chunk_end = self._calculate_range(chunk_start) + return await self._download_chunk(chunk_start, chunk_end - 1) + + async def _update_progress(self, length: int) -> None: + if self.progress_lock_async: + async with self.progress_lock_async: + self.progress_total += length + else: + self.progress_total += length + + if self.progress_hook: + await cast(Callable[[int, Optional[int]], Awaitable[Any]], self.progress_hook)( + self.progress_total, self.total_size) + + async def _write_to_stream(self, chunk_data: bytes, chunk_start: int) -> None: + if self.stream_lock_async: + async with self.stream_lock_async: + self.stream.seek(self.stream_start + (chunk_start - self.start_index)) + self.stream.write(chunk_data) + else: + self.stream.write(chunk_data) + + async def _download_chunk(self, chunk_start: int, chunk_end: int) -> bytes: + range_header, range_validation = validate_and_format_range_headers( + chunk_start, + chunk_end, + check_content_md5=self.validate_content + ) + try: + _, response = await cast(Awaitable[Any], self.client.download( + range=range_header, + range_get_content_md5=range_validation, + validate_content=self.validate_content, + data_stream_total=self.total_size, + download_stream_current=self.progress_total, + **self.request_options + )) + if response.properties.etag != self.etag: + raise ResourceModifiedError(message="The file has been modified while downloading.") + except HttpResponseError as error: + process_storage_error(error) + + chunk_data = await process_content(response) + return chunk_data + + +class _AsyncChunkIterator(object): + """Async iterator for chunks in file download stream.""" + + def __init__(self, size: int, content: bytes, downloader: Optional[_AsyncChunkDownloader], chunk_size: int) -> None: + self.size = size + self._chunk_size = chunk_size + self._current_content = content + self._iter_downloader = downloader + self._iter_chunks: Optional[Generator[int, None, None]] = None + self._complete = size == 0 + + def __len__(self) -> int: + return self.size + + def __iter__(self) -> None: + raise TypeError("Async stream must be iterated asynchronously.") + + def __aiter__(self) -> AsyncIterator[bytes]: + return self + + async def __anext__(self) -> bytes: + if self._complete: + raise StopAsyncIteration("Download complete") + if not self._iter_downloader: + # cut the data obtained from initial GET into chunks + if len(self._current_content) > self._chunk_size: + return self._get_chunk_data() + self._complete = True + return self._current_content + + if not self._iter_chunks: + self._iter_chunks = self._iter_downloader.get_chunk_offsets() + + # initial GET result still has more than _chunk_size bytes of data + if len(self._current_content) >= self._chunk_size: + return self._get_chunk_data() + + try: + chunk = next(self._iter_chunks) + self._current_content += await self._iter_downloader.yield_chunk(chunk) + except StopIteration as exc: + self._complete = True + # it's likely that there some data left in self._current_content + if self._current_content: + return self._current_content + raise StopAsyncIteration("Download complete") from exc + + return self._get_chunk_data() + + def _get_chunk_data(self) -> bytes: + chunk_data = self._current_content[: self._chunk_size] + self._current_content = self._current_content[self._chunk_size:] + return chunk_data + + +class StorageStreamDownloader(object): # pylint: disable=too-many-instance-attributes + """A streaming object to download from Azure Storage.""" + + name: str + """The name of the file being downloaded.""" + path: str + """The full path of the file.""" + share: str + """The name of the share where the file is.""" + properties: "FileProperties" + """The properties of the file being downloaded. If only a range of the data is being + downloaded, this will be reflected in the properties.""" + size: int + """The size of the total data in the stream. This will be the byte range if specified, + otherwise the total size of the file.""" + + def __init__( + self, client: "FileOperations" = None, # type: ignore [assignment] + config: "StorageConfiguration" = None, # type: ignore [assignment] + start_range: Optional[int] = None, + end_range: Optional[int] = None, + validate_content: bool = None, # type: ignore [assignment] + max_concurrency: int = 1, + name: str = None, # type: ignore [assignment] + path: str = None, # type: ignore [assignment] + share: str = None, # type: ignore [assignment] + encoding: Optional[str] = None, + **kwargs: Any + ) -> None: + self.name = name + self.path = path + self.share = share + self.size = 0 + + self._client = client + self._config = config + self._start_range = start_range + self._end_range = end_range + self._max_concurrency = max_concurrency + self._encoding = encoding + self._validate_content = validate_content + self._progress_hook = kwargs.pop('progress_hook', None) + self._request_options = kwargs + self._location_mode = None + self._download_complete = False + self._current_content = b"" + self._file_size = 0 + self._response = None + self._etag = "" + + # The service only provides transactional MD5s for chunks under 4MB. + # If validate_content is on, get only self.MAX_CHUNK_GET_SIZE for the first + # chunk so a transactional MD5 can be retrieved. + self._first_get_size = self._config.max_single_get_size if not self._validate_content \ + else self._config.max_chunk_get_size + initial_request_start = self._start_range or 0 + if self._end_range is not None and self._end_range - initial_request_start < self._first_get_size: + initial_request_end = self._end_range + else: + initial_request_end = initial_request_start + self._first_get_size - 1 + + self._initial_range = (initial_request_start, initial_request_end) + + def __len__(self) -> int: + return self.size + + async def _setup(self) -> None: + self._response = await self._initial_request() + self.properties = self._response.properties # type: ignore [attr-defined] + self.properties.name = self.name + self.properties.path = self.path + self.properties.share = self.share + + # Set the content length to the download size instead of the size of + # the last range + self.properties.size = self.size + + # Overwrite the content range to the user requested range + self.properties.content_range = f'bytes {self._start_range}-{self._end_range}/{self._file_size}' + + # Overwrite the content MD5 as it is the MD5 for the last range instead + # of the stored MD5 + # TODO: Set to the stored MD5 when the service returns this + self.properties.content_md5 = None # type: ignore [attr-defined] + + if self.size == 0: + self._current_content = b"" + else: + self._current_content = await process_content(self._response) + + async def _initial_request(self): + range_header, range_validation = validate_and_format_range_headers( + self._initial_range[0], + self._initial_range[1], + start_range_required=False, + end_range_required=False, + check_content_md5=self._validate_content) + + try: + location_mode, response = cast(Tuple[Optional[str], Any], await self._client.download( + range=range_header, + range_get_content_md5=range_validation, + validate_content=self._validate_content, + data_stream_total=None, + download_stream_current=0, + **self._request_options + )) + + # Check the location we read from to ensure we use the same one + # for subsequent requests. + self._location_mode = location_mode + + # Parse the total file size and adjust the download size if ranges + # were specified + self._file_size = parse_length_from_content_range(response.properties.content_range) + if self._file_size is None: + raise ValueError("Required Content-Range response header is missing or malformed.") + + if self._end_range is not None: + # Use the length unless it is over the end of the file + self.size = min(self._file_size, self._end_range - self._start_range + 1) + elif self._start_range is not None: + self.size = self._file_size - self._start_range + else: + self.size = self._file_size + + except HttpResponseError as error: + if self._start_range is None and error.response and error.response.status_code == 416: + # Get range will fail on an empty file. If the user did not + # request a range, do a regular get request in order to get + # any properties. + try: + _, response = cast(Tuple[Optional[Any], Any], await self._client.download( + validate_content=self._validate_content, + data_stream_total=0, + download_stream_current=0, + **self._request_options + )) + except HttpResponseError as e: + process_storage_error(e) + + # Set the download size to empty + self.size = 0 + self._file_size = 0 + else: + process_storage_error(error) + + # If the file is small, the download is complete at this point. + # If file size is large, download the rest of the file in chunks. + if response.properties.size == self.size: + self._download_complete = True + self._etag = response.properties.etag + return response + + def chunks(self) -> AsyncIterator[bytes]: + """ + Iterate over chunks in the download stream. + + :return: An iterator of the chunks in the download stream. + :rtype: AsyncIterator[bytes] + """ + if self.size == 0 or self._download_complete: + iter_downloader = None + else: + data_end = self._file_size + if self._end_range is not None: + # Use the length unless it is over the end of the file + data_end = min(self._file_size, self._end_range + 1) + iter_downloader = _AsyncChunkDownloader( + client=self._client, + total_size=self.size, + chunk_size=self._config.max_chunk_get_size, + current_progress=self._first_get_size, + start_range=self._initial_range[1] + 1, # Start where the first download ended + end_range=data_end, + stream=None, + parallel=False, + validate_content=self._validate_content, + use_location=self._location_mode, + etag=self._etag, + **self._request_options) + return _AsyncChunkIterator( + size=self.size, + content=self._current_content, + downloader=iter_downloader, + chunk_size=self._config.max_chunk_get_size + ) + + async def readall(self) -> bytes: + """Download the contents of this file. + + This operation is blocking until all data is downloaded. + :return: The entire blob content as bytes + :rtype: bytes + """ + stream = BytesIO() + await self.readinto(stream) + data = stream.getvalue() + if self._encoding: + return data.decode(self._encoding) # type: ignore [return-value] + return data + + async def content_as_bytes(self, max_concurrency=1): + """DEPRECATED: Download the contents of this file. + + This operation is blocking until all data is downloaded. + + This method is deprecated, use func:`readall` instead. + + :param int max_concurrency: + The number of parallel connections with which to download. + :return: The contents of the file as bytes. + :rtype: bytes + """ + warnings.warn( + "content_as_bytes is deprecated, use readall instead", + DeprecationWarning + ) + self._max_concurrency = max_concurrency + return await self.readall() + + async def content_as_text(self, max_concurrency=1, encoding="UTF-8"): + """DEPRECATED: Download the contents of this file, and decode as text. + + This operation is blocking until all data is downloaded. + + This method is deprecated, use func:`readall` instead. + + :param int max_concurrency: + The number of parallel connections with which to download. + :param str encoding: + Test encoding to decode the downloaded bytes. Default is UTF-8. + :return: The contents of the file as a str. + :rtype: str + """ + warnings.warn( + "content_as_text is deprecated, use readall instead", + DeprecationWarning + ) + self._max_concurrency = max_concurrency + self._encoding = encoding + return await self.readall() + + async def readinto(self, stream: IO[bytes]) -> int: + """Download the contents of this file to a stream. + + :param IO[bytes] stream: + The stream to download to. This can be an open file-handle, + or any writable stream. The stream must be seekable if the download + uses more than one parallel connection. + :returns: The number of bytes read. + :rtype: int + """ + # the stream must be seekable if parallel download is required + parallel = self._max_concurrency > 1 + if parallel: + error_message = "Target stream handle must be seekable." + if sys.version_info >= (3,) and not stream.seekable(): + raise ValueError(error_message) + + try: + stream.seek(stream.tell()) + except (NotImplementedError, AttributeError) as exc: + raise ValueError(error_message) from exc + + # Write the content to the user stream + stream.write(self._current_content) + if self._progress_hook: + await self._progress_hook(len(self._current_content), self.size) + + if self._download_complete: + return self.size + + data_end = self._file_size + if self._end_range is not None: + # Use the length unless it is over the end of the file + data_end = min(self._file_size, self._end_range + 1) + + downloader = _AsyncChunkDownloader( + client=self._client, + total_size=self.size, + chunk_size=self._config.max_chunk_get_size, + current_progress=self._first_get_size, + start_range=self._initial_range[1] + 1, # start where the first download ended + end_range=data_end, + stream=stream, + parallel=parallel, + validate_content=self._validate_content, + use_location=self._location_mode, + progress_hook=self._progress_hook, + etag=self._etag, + **self._request_options) + + dl_tasks = downloader.get_chunk_offsets() + running_futures = { + asyncio.ensure_future(downloader.process_chunk(d)) + for d in islice(dl_tasks, 0, self._max_concurrency) + } + while running_futures: + # Wait for some download to finish before adding a new one + done, running_futures = await asyncio.wait( + running_futures, return_when=asyncio.FIRST_COMPLETED) + try: + for task in done: + task.result() + except HttpResponseError as error: + process_storage_error(error) + try: + for _ in range(0, len(done)): + next_chunk = next(dl_tasks) + running_futures.add(asyncio.ensure_future(downloader.process_chunk(next_chunk))) + except StopIteration: + break + + if running_futures: + # Wait for the remaining downloads to finish + done, _running_futures = await asyncio.wait(running_futures) + try: + for task in done: + task.result() + except HttpResponseError as error: + process_storage_error(error) + return self.size + + async def download_to_stream(self, stream, max_concurrency=1): + """Download the contents of this file to a stream. + + This method is deprecated, use func:`readinto` instead. + + :param IO stream: + The stream to download to. This can be an open file-handle, + or any writable stream. The stream must be seekable if the download + uses more than one parallel connection. + :param int max_concurrency: + The number of parallel connections with which to download. + :returns: The properties of the downloaded file. + :rtype: Any + """ + warnings.warn( + "download_to_stream is deprecated, use readinto instead", + DeprecationWarning + ) + self._max_concurrency = max_concurrency + await self.readinto(stream) + return self.properties diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_file_client_async.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_file_client_async.py new file mode 100644 index 00000000..6272949b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_file_client_async.py @@ -0,0 +1,1740 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=too-many-lines, too-many-public-methods, docstring-keyword-should-match-keyword-only + +import functools +import sys +import time +import warnings +from datetime import datetime +from io import BytesIO +from typing import ( + Any, AnyStr, AsyncGenerator, AsyncIterable, Callable, cast, + Dict, IO, Iterable, List, Optional, Tuple, Union, + TYPE_CHECKING +) +from typing_extensions import Self + +from azure.core.async_paging import AsyncItemPaged +from azure.core.exceptions import HttpResponseError, ResourceNotFoundError +from azure.core.tracing.decorator import distributed_trace +from azure.core.tracing.decorator_async import distributed_trace_async +from .._deserialize import deserialize_file_properties, deserialize_file_stream, get_file_ranges_result +from .._file_client_helpers import ( + _format_url, + _from_file_url, + _get_ranges_options, + _parse_url, + _upload_range_from_url_options +) +from .._generated.aio import AzureFileStorage +from .._generated.models import FileHTTPHeaders +from .._parser import _datetime_to_str, _get_file_permission, _parse_snapshot +from .._serialize import ( + get_access_conditions, + get_api_version, + get_dest_access_conditions, + get_rename_smb_properties, + get_smb_properties, + get_source_access_conditions +) +from .._shared.base_client import StorageAccountHostsMixin, parse_query +from .._shared.base_client_async import AsyncStorageAccountHostsMixin, parse_connection_str +from .._shared.policies_async import ExponentialRetry +from .._shared.request_handlers import add_metadata_headers, get_length +from .._shared.response_handlers import process_storage_error, return_response_headers +from .._shared.uploads_async import AsyncIterStreamer, FileChunkUploader, IterStreamer, upload_data_chunks +from ._download_async import StorageStreamDownloader +from ._lease_async import ShareLeaseClient +from ._models import FileProperties, Handle, HandlesPaged + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + +if TYPE_CHECKING: + from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential + from azure.core.credentials_async import AsyncTokenCredential + from .._models import ContentSettings, NTFSAttributes + from .._shared.base_client import StorageConfiguration + + +async def _upload_file_helper( + client: "ShareFileClient", + stream: Any, + size: Optional[int], + metadata: Optional[Dict[str, str]], + content_settings: Optional["ContentSettings"], + validate_content: bool, + timeout: Optional[int], + max_concurrency: int, + file_settings: "StorageConfiguration", + file_attributes: Optional[Union[str, "NTFSAttributes"]] = None, + file_creation_time: Optional[Union[str, datetime]] = None, + file_last_write_time: Optional[Union[str, datetime]] = None, + file_permission: Optional[str] = None, + file_permission_key: Optional[str] = None, + progress_hook: Optional[Callable[[int, Optional[int]], None]] = None, + **kwargs: Any +) -> Dict[str, Any]: + try: + if size is None or size < 0: + raise ValueError("A content size must be specified for a File.") + response = await client.create_file( + size, content_settings=content_settings, metadata=metadata, + file_attributes=file_attributes, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + file_permission=file_permission, + permission_key=file_permission_key, + timeout=timeout, + **kwargs + ) + if size == 0: + return response + + responses = await upload_data_chunks( + service=client, + uploader_class=FileChunkUploader, + total_size=size, + chunk_size=file_settings.max_range_size, + stream=stream, + max_concurrency=max_concurrency, + validate_content=validate_content, + progress_hook=progress_hook, + timeout=timeout, + **kwargs + ) + return cast(Dict[str, Any], sorted(responses, key=lambda r: r.get('last_modified'))[-1]) + except HttpResponseError as error: + process_storage_error(error) + + +class ShareFileClient(AsyncStorageAccountHostsMixin, StorageAccountHostsMixin): # type: ignore [misc] + """A client to interact with a specific file, although that file may not yet exist. + + :param str account_url: + The URI to the storage account. In order to create a client given the full URI to the + file, use the :func:`from_file_url` classmethod. + :param share_name: + The name of the share for the file. + :type share_name: str + :param str file_path: + The file path to the file with which to interact. If specified, this value will override + a file value specified in the file URL. + :param str snapshot: + An optional file snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`ShareClient.create_snapshot`. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a AsyncTokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials_async.AsyncTokenCredential or + str or dict[str, str] or None + :keyword token_intent: + Required when using `AsyncTokenCredential` for authentication and ignored for other forms of authentication. + Specifies the intent for all requests when using `AsyncTokenCredential` authentication. Possible values are: + + backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory + ACLs are bypassed and full permissions are granted. User must also have required RBAC permission. + + :paramtype token_intent: Literal['backup'] + :keyword bool allow_trailing_dot: If true, the trailing dot will not be trimmed from the target URI. + :keyword bool allow_source_trailing_dot: If true, the trailing dot will not be trimmed from the source URI. + :keyword str api_version: + The Storage API version to use for requests. Default value is the most recent service version that is + compatible with the current SDK. Setting to an older version may result in reduced feature compatibility. + + .. versionadded:: 12.1.0 + + :keyword str secondary_hostname: + The hostname of the secondary endpoint. + :keyword int max_range_size: The maximum range size used for a file upload. Defaults to 4*1024*1024. + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type AsyncTokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.blob.core.windows.net. + """ + def __init__( + self, account_url: str, + share_name: str, + file_path: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long + *, + token_intent: Optional[Literal['backup']] = None, + **kwargs: Any + ) -> None: + kwargs["retry_policy"] = kwargs.get("retry_policy") or ExponentialRetry(**kwargs) + loop = kwargs.pop('loop', None) + if loop and sys.version_info >= (3, 8): + warnings.warn("The 'loop' parameter was deprecated from asyncio's high-level" + "APIs in Python 3.8 and is no longer supported.", DeprecationWarning) + if hasattr(credential, 'get_token') and not token_intent: + raise ValueError("'token_intent' keyword is required when 'credential' is an AsyncTokenCredential.") + parsed_url = _parse_url(account_url, share_name, file_path) + path_snapshot, sas_token = parse_query(parsed_url.query) + if not sas_token and not credential: + raise ValueError( + 'You need to provide either an account shared key or SAS token when creating a storage service.') + self.snapshot = _parse_snapshot(snapshot, path_snapshot) + self.share_name = share_name + self.file_path = file_path.split('/') + self.file_name = self.file_path[-1] + self.directory_path = "/".join(self.file_path[:-1]) + + self._query_str, credential = self._format_query_string( + sas_token, credential, share_snapshot=self.snapshot) + super(ShareFileClient, self).__init__( + parsed_url, service='file-share', credential=credential, **kwargs) + self.allow_trailing_dot = kwargs.pop('allow_trailing_dot', None) + self.allow_source_trailing_dot = kwargs.pop('allow_source_trailing_dot', None) + self.file_request_intent = token_intent + self._client = AzureFileStorage(url=self.url, base_url=self.url, pipeline=self._pipeline, + allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, + file_request_intent=self.file_request_intent) + self._client._config.version = get_api_version(kwargs) # type: ignore [assignment] + + @classmethod + def from_file_url( + cls, file_url: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """A client to interact with a specific file, although that file may not yet exist. + + :param str file_url: The full URI to the file. + :param str snapshot: + An optional file snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`ShareClient.create_snapshot`. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a AsyncTokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials_async.AsyncTokenCredential or + str or dict[str, str] or None + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type AsyncTokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.file.core.windows.net. + :returns: A File client. + :rtype: ~azure.storage.fileshare.ShareFileClient + """ + account_url, share_name, file_path, snapshot = _from_file_url(file_url, snapshot) + return cls(account_url, share_name, file_path, snapshot, credential, **kwargs) + + def _format_url(self, hostname: str): + return _format_url(self.scheme, hostname, self.share_name, self.file_path, self._query_str) + + @classmethod + def from_connection_string( + cls, conn_str: str, + share_name: str, + file_path: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """Create ShareFileClient from a Connection String. + + :param str conn_str: + A connection string to an Azure Storage account. + :param share_name: The name of the share. + :type share_name: str + :param str file_path: + The file path. + :param str snapshot: + An optional file snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`ShareClient.create_snapshot`. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a AsyncTokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials_async.AsyncTokenCredential or + str or dict[str, str] or None + :keyword str audience: The audience to use when requesting tokens for Azure Active Directory + authentication. Only has an effect when credential is of type AsyncTokenCredential. The value could be + https://storage.azure.com/ (default) or https://<account>.file.core.windows.net. + :returns: A File client. + :rtype: ~azure.storage.fileshare.ShareFileClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_hello_world_async.py + :start-after: [START create_file_client] + :end-before: [END create_file_client] + :language: python + :dedent: 12 + :caption: Creates the file client with connection string. + """ + account_url, secondary, credential = parse_connection_str(conn_str, credential, 'file') + if 'secondary_hostname' not in kwargs: + kwargs['secondary_hostname'] = secondary + return cls( + account_url, share_name=share_name, file_path=file_path, snapshot=snapshot, credential=credential, **kwargs) + + @distributed_trace_async + async def acquire_lease(self, lease_id: Optional[str] = None, **kwargs: Any) -> ShareLeaseClient: + """Requests a new lease. + + If the file does not have an active lease, the File + Service creates a lease on the blob and returns a new lease. + + :param str lease_id: + Proposed lease ID, in a GUID string format. The File Service + returns 400 (Invalid request) if the proposed lease ID is not + in the correct format. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: A ShareLeaseClient object. + :rtype: ~azure.storage.fileshare.aio.ShareLeaseClient + """ + kwargs['lease_duration'] = -1 + lease = ShareLeaseClient(self, lease_id=lease_id) + await lease.acquire(**kwargs) + return lease + + @distributed_trace_async + async def exists(self, **kwargs: Any) -> bool: + """ + Returns True if the file exists and returns False otherwise. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: True if the file exists, False otherwise. + :rtype: bool + """ + try: + await self._client.file.get_properties(**kwargs) + return True + except HttpResponseError as error: + try: + process_storage_error(error) + except ResourceNotFoundError: + return False + + @distributed_trace_async + async def create_file( + self, size: int, + file_attributes: Optional[Union[str, "NTFSAttributes"]] = None, + file_creation_time: Optional[Union[str, datetime]] = None, + file_last_write_time: Optional[Union[str, datetime]] = None, + file_permission: Optional[str] = None, + permission_key: Optional[str] = None, + **kwargs: Any + ) -> Dict[str, Any]: + """Creates a new file. + + Note that it only initializes the file with no content. + + :param int size: Specifies the maximum size for the file, + up to 1 TB. + :param file_attributes: + The file system attributes for files and directories. + If not set, the default value would be "None" and the attributes will be set to "Archive". + Here is an example for when the var type is str: 'Temporary|Archive'. + file_attributes value is not case sensitive. + :type file_attributes: str or ~azure.storage.fileshare.NTFSAttributes or None + :param file_creation_time: Creation time for the file + :type file_creation_time: str or ~datetime.datetime or None + :param file_last_write_time: Last write time for the file + :type file_last_write_time: str or ~datetime.datetime or None + :param file_permission: If specified the permission (security + descriptor) shall be set for the directory/file. This header can be + used if Permission size is <= 8KB, else x-ms-file-permission-key + header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the + x-ms-file-permission or x-ms-file-permission-key should be specified. + :type file_permission: str + :param permission_key: Key of the permission to be set for the + directory/file. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. + :type permission_key: str + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_change_time: + Change time for the file. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword ~azure.storage.fileshare.ContentSettings content_settings: + ContentSettings object used to set file properties. Used to set content type, encoding, + language, disposition, md5, and cache control. + :keyword metadata: + Name-value pairs associated with the file as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str + :keyword str owner: + NFS only. The owner of the file. + :keyword str group: + NFS only. The owning group of the file. + :keyword str file_mode: + NFS only. The file mode of the file. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_client_async.py + :start-after: [START create_file] + :end-before: [END create_file] + :language: python + :dedent: 16 + :caption: Create a file. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + content_settings = kwargs.pop('content_settings', None) + metadata = kwargs.pop('metadata', None) + timeout = kwargs.pop('timeout', None) + headers = kwargs.pop("headers", {}) + headers.update(add_metadata_headers(metadata)) + file_http_headers = None + if content_settings: + file_http_headers = FileHTTPHeaders( + file_cache_control=content_settings.cache_control, + file_content_type=content_settings.content_type, + file_content_md5=bytearray(content_settings.content_md5) if content_settings.content_md5 else None, + file_content_encoding=content_settings.content_encoding, + file_content_language=content_settings.content_language, + file_content_disposition=content_settings.content_disposition, + ) + file_permission = _get_file_permission(file_permission, permission_key, None) + file_change_time = kwargs.pop('file_change_time', None) + try: + return cast(Dict[str, Any], await self._client.file.create( + file_content_length=size, + metadata=metadata, + file_attributes=str(file_attributes) if file_attributes is not None else file_attributes, + file_creation_time=_datetime_to_str(file_creation_time), + file_last_write_time=_datetime_to_str(file_last_write_time), + file_change_time=_datetime_to_str(file_change_time), + file_permission=file_permission, + file_permission_key=permission_key, + file_http_headers=file_http_headers, + lease_access_conditions=access_conditions, + headers=headers, + timeout=timeout, + cls=return_response_headers, + **kwargs + )) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def upload_file( + self, data: Union[bytes, str, Iterable[AnyStr], AsyncIterable[AnyStr], IO[AnyStr]], + length: Optional[int] = None, + file_attributes: Optional[Union[str, "NTFSAttributes"]] = None, + file_creation_time: Optional[Union[str, datetime]] = None, + file_last_write_time: Optional[Union[str, datetime]] = None, + file_permission: Optional[str] = None, + permission_key: Optional[str] = None, + **kwargs + ) -> Dict[str, Any]: + """Uploads a new file. + + :param data: + Content of the file. + :type data: Union[bytes, str, Iterable[AnyStr], AsyncIterable[AnyStr], IO[AnyStr]] + :param int length: + Length of the file in bytes. Specify its maximum size, up to 1 TiB. + :param file_attributes: + The file system attributes for files and directories. + If not set, the default value would be "None" and the attributes will be set to "Archive". + Here is an example for when the var type is str: 'Temporary|Archive'. + file_attributes value is not case sensitive. + :type file_attributes: str or ~azure.storage.fileshare.NTFSAttributes or None + :param file_creation_time: Creation time for the file + :type file_creation_time: str or ~datetime.datetime or None + :param file_last_write_time: Last write time for the file + :type file_last_write_time: str or ~datetime.datetime or None + :param file_permission: If specified the permission (security + descriptor) shall be set for the directory/file. This header can be + used if Permission size is <= 8KB, else x-ms-file-permission-key + header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the + x-ms-file-permission or x-ms-file-permission-key should be specified. + :type file_permission: str + :param permission_key: Key of the permission to be set for the + directory/file. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. + :type permission_key: str + :keyword file_change_time: + Change time for the file. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword metadata: + Name-value pairs associated with the file as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword ~azure.storage.fileshare.ContentSettings content_settings: + ContentSettings object used to set file properties. Used to set content type, encoding, + language, disposition, md5, and cache control. + :keyword bool validate_content: + If true, calculates an MD5 hash for each range of the file. The storage + service checks the hash of the content that has arrived with the hash + that was sent. This is primarily valuable for detecting bitflips on + the wire if using http instead of https as https (the default) will + already validate. Note that this MD5 hash is not stored with the + file. + :keyword int max_concurrency: + Maximum number of parallel connections to use when transferring the file in chunks. + This option does not affect the underlying connection pool, and may + require a separate configuration of the connection pool. + :keyword str encoding: + Defaults to UTF-8. + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str + :keyword progress_hook: + An async callback to track the progress of a long running upload. The signature is + function(current: int, total: Optional[int]) where current is the number of bytes transferred + so far, and total is the size of the blob or None if the size is unknown. + :paramtype progress_hook: Callable[[int, Optional[int]], Awaitable[None]] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_client_async.py + :start-after: [START upload_file] + :end-before: [END upload_file] + :language: python + :dedent: 16 + :caption: Upload a file. + """ + metadata = kwargs.pop('metadata', None) + content_settings = kwargs.pop('content_settings', None) + max_concurrency = kwargs.pop('max_concurrency', 1) + validate_content = kwargs.pop('validate_content', False) + progress_hook = kwargs.pop('progress_hook', None) + timeout = kwargs.pop('timeout', None) + encoding = kwargs.pop('encoding', 'UTF-8') + + if isinstance(data, str): + data = data.encode(encoding) + if length is None: + length = get_length(data) + if isinstance(data, bytes): + data = data[:length] + + stream: Optional[Any] = None + if isinstance(data, bytes): + stream = BytesIO(data) + elif hasattr(data, "read"): + stream = data + elif hasattr(data, "__iter__"): + stream = IterStreamer(data, encoding=encoding) + elif hasattr(data, '__aiter__'): + stream = AsyncIterStreamer(cast(AsyncGenerator, data), encoding=encoding) + else: + raise TypeError(f"Unsupported data type: {type(data)}") + return await _upload_file_helper( + self, + stream, + length, + metadata, + content_settings, + validate_content, + timeout, + max_concurrency, + self._config, + file_attributes=file_attributes, + file_creation_time=file_creation_time, + file_last_write_time=file_last_write_time, + file_permission=file_permission, + file_permission_key=permission_key, + progress_hook=progress_hook, + **kwargs) + + @distributed_trace_async + async def start_copy_from_url(self, source_url: str, **kwargs: Any) -> Dict[str, Any]: + """Initiates the copying of data from a source URL into the file + referenced by the client. + + The status of this copy operation can be found using the `get_properties` + method. + + :param str source_url: + Specifies the URL of the source file. + :keyword str file_permission: + If specified the permission (security descriptor) shall be set for the directory/file. + This value can be set to "source" to copy the security descriptor from the source file. + Otherwise if set, this value will be used to override the source value. If not set, permission value + is inherited from the parent directory of the target file. This setting can be + used if Permission size is <= 8KB, otherwise permission_key shall be used. + If SDDL is specified as input, it must have owner, group and dacl. + Note: Only one of the file_permission or permission_key should be specified. + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :keyword str permission_key: + Key of the permission to be set for the directory/file. + This value can be set to "source" to copy the security descriptor from the source file. + Otherwise if set, this value will be used to override the source value. If not set, permission value + is inherited from the parent directory of the target file. + Note: Only one of the file_permission or permission_key should be specified. + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_attributes: + This value can be set to "source" to copy file attributes from the source file to the target file, + or to clear all attributes, it can be set to "None". Otherwise it can be set to a list of attributes + to set on the target file. If this is not set, the default value is "Archive". + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :paramtype file_attributes: str or ~azure.storage.fileshare.NTFSAttributes + :keyword file_creation_time: + This value can be set to "source" to copy the creation time from the source file to the target file, + or a datetime to set as creation time on the target file. This could also be a string in ISO 8601 format. + If this is not set, creation time will be set to the date time value of the creation + (or when it was overwritten) of the target file by copy engine. + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :paramtype file_creation_time: str or ~datetime.datetime + :keyword file_last_write_time: + This value can be set to "source" to copy the last write time from the source file to the target file, or + a datetime to set as the last write time on the target file. This could also be a string in ISO 8601 format. + If this is not set, value will be the last write time to the file by the copy engine. + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :paramtype file_last_write_time: str or ~datetime.datetime + :keyword file_change_time: + Change time for the file. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.9.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword bool ignore_read_only: + Specifies the option to overwrite the target file if it already exists and has read-only attribute set. + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :keyword bool set_archive_attribute: + Specifies the option to set the archive attribute on the target file. + True means the archive attribute will be set on the target file despite attribute + overrides or the source file state. + + .. versionadded:: 12.1.0 + + This parameter was introduced in API version '2019-07-07'. + + :keyword metadata: + Name-value pairs associated with the file as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str + :keyword str owner: + NFS only. The owner of the file. + :keyword str group: + NFS only. The owning group of the file. + :keyword str file_mode: + NFS only. The file mode of the file. + :keyword file_mode_copy_mode: + NFS only. Applicable only when the copy source is a File. Determines the copy behavior + of the mode bits of the file. Possible values are: + + source - The mode on the destination file is copied from the source file. + override - The mode on the destination file is determined via the file_mode keyword. + :paramtype file_mode_copy_mode: Literal['source', 'override'] + :keyword owner_copy_mode: + NFS only. Applicable only when the copy source is a File. Determines the copy behavior + of the owner and group of the file. Possible values are: + + source - The owner and group on the destination file is copied from the source file. + override - The owner and group on the destination file is determined via the owner and group keywords. + :paramtype owner_copy_mode: Literal['source', 'override'] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: Response after data copying operation has been initiated. + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_client_async.py + :start-after: [START copy_file_from_url] + :end-before: [END copy_file_from_url] + :language: python + :dedent: 16 + :caption: Copy a file from a URL + """ + metadata = kwargs.pop('metadata', None) + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + owner = kwargs.pop('owner', None) + group = kwargs.pop('group', None) + file_mode = kwargs.pop('file_mode', None) + file_mode_copy_mode = kwargs.pop('file_mode_copy_mode', None) + file_owner_copy_mode = kwargs.pop('owner_copy_mode', None) + headers = kwargs.pop("headers", {}) + headers.update(add_metadata_headers(metadata)) + kwargs.update(get_smb_properties(kwargs)) + try: + return cast(Dict[str, Any], await self._client.file.start_copy( + source_url, + metadata=metadata, + lease_access_conditions=access_conditions, + owner=owner, + group=group, + file_mode=file_mode, + file_mode_copy_mode=file_mode_copy_mode, + file_owner_copy_mode=file_owner_copy_mode, + headers=headers, + cls=return_response_headers, + timeout=timeout, + **kwargs + )) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def abort_copy(self, copy_id: Union[str, FileProperties], **kwargs: Any) -> None: + """Abort an ongoing copy operation. + + This will leave a destination file with zero length and full metadata. + This will raise an error if the copy operation has already ended. + + :param copy_id: + The copy operation to abort. This can be either an ID, or an + instance of FileProperties. + :type copy_id: str or ~azure.storage.fileshare.FileProperties + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + if isinstance(copy_id, FileProperties): + copy_id = copy_id.copy.id + elif isinstance(copy_id, Dict): + copy_id = copy_id['copy_id'] + try: + await self._client.file.abort_copy(copy_id=copy_id, + lease_access_conditions=access_conditions, + timeout=timeout, **kwargs) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def download_file( + self, offset: Optional[int] = None, + length: Optional[int] = None, + **kwargs: Any + ) -> StorageStreamDownloader: + """Downloads a file to the StorageStreamDownloader. The readall() method must + be used to read all the content or readinto() must be used to download the file into + a stream. Using chunks() returns an async iterator which allows the user to iterate over the content in chunks. + + :param int offset: + Start of byte range to use for downloading a section of the file. + Must be set if length is provided. + :param int length: + Number of bytes to read from the stream. This is optional, but + should be supplied for optimal performance. + :keyword int max_concurrency: + Maximum number of parallel connections to use when transferring the file in chunks. + This option does not affect the underlying connection pool, and may + require a separate configuration of the connection pool. + :keyword bool validate_content: + If true, calculates an MD5 hash for each chunk of the file. The storage + service checks the hash of the content that has arrived with the hash + that was sent. This is primarily valuable for detecting bitflips on + the wire if using http instead of https as https (the default) will + already validate. Note that this MD5 hash is not stored with the + file. Also note that if enabled, the memory-efficient upload algorithm + will not be used, because computing the MD5 hash requires buffering + entire blocks, and doing so defeats the purpose of the memory-efficient algorithm. + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str + :keyword progress_hook: + An async callback to track the progress of a long running download. The signature is + function(current: int, total: int) where current is the number of bytes transferred + so far, and total is the size of the blob or None if the size is unknown. + :paramtype progress_hook: Callable[[int, int], Awaitable[None]] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: A streaming object (StorageStreamDownloader) + :rtype: ~azure.storage.fileshare.aio.StorageStreamDownloader + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_client_async.py + :start-after: [START download_file] + :end-before: [END download_file] + :language: python + :dedent: 16 + :caption: Download a file. + """ + if length is not None and offset is None: + raise ValueError("Offset value must not be None if length is set.") + + range_end = None + if length is not None: + if offset is None: + raise ValueError("Offset value must not be None if length is set.") + range_end = offset + length - 1 # Service actually uses an end-range inclusive index + + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + + downloader = StorageStreamDownloader( + client=self._client.file, + config=self._config, + start_range=offset, + end_range=range_end, + name=self.file_name, + path='/'.join(self.file_path), + share=self.share_name, + lease_access_conditions=access_conditions, + cls=deserialize_file_stream, + **kwargs + ) + await downloader._setup() # pylint: disable=protected-access + return downloader + + @distributed_trace_async + async def delete_file(self, **kwargs: Any) -> None: + """Marks the specified file for deletion. The file is + later deleted during garbage collection. + + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_client_async.py + :start-after: [START delete_file] + :end-before: [END delete_file] + :language: python + :dedent: 16 + :caption: Delete a file. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + await self._client.file.delete(lease_access_conditions=access_conditions, timeout=timeout, **kwargs) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def rename_file(self, new_name: str, **kwargs: Any) -> "ShareFileClient": + """ + Rename the source file. + + :param str new_name: + The new file name. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword bool overwrite: + A boolean value for if the destination file already exists, whether this request will + overwrite the file or not. If true, the rename will succeed and will overwrite the + destination file. If not provided or if false and the destination file does exist, the + request will not overwrite the destination file. If provided and the destination file + doesn't exist, the rename will succeed. + :keyword bool ignore_read_only: + A boolean value that specifies whether the ReadOnly attribute on a preexisting destination + file should be respected. If true, the rename will succeed, otherwise, a previous file at the + destination with the ReadOnly attribute set will cause the rename to fail. + :keyword str file_permission: + If specified the permission (security descriptor) shall be set for the file. This header + can be used if Permission size is <= 8KB, else file_permission_key shall be used. + If SDDL is specified as input, it must have owner, group and dacl. + A value of 'preserve' can be passed to preserve source permissions. + Note: Only one of the file_permission or file_permission_key should be specified. + :keyword str file_permission_key: + Key of the permission to be set for the file. + Note: Only one of the file-permission or file-permission-key should be specified. + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_attributes: + The file system attributes for the file. + :paramtype file_attributes: ~azure.storage.fileshare.NTFSAttributes or str + :keyword file_creation_time: + Creation time for the file. + :paramtype file_creation_time: ~datetime.datetime or str + :keyword file_last_write_time: + Last write time for the file. + :paramtype file_last_write_time: ~datetime.datetime or str + :keyword file_change_time: + Change time for the file. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword str content_type: + The Content Type of the new file. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :keyword Dict[str,str] metadata: + A name-value pair to associate with a file storage object. + :keyword source_lease: + Required if the source file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + :paramtype source_lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword destination_lease: + Required if the destination file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + :paramtype destination_lease: ~azure.storage.fileshare.ShareLeaseClient or str + :returns: The new File Client. + :rtype: ~azure.storage.fileshare.ShareFileClient + """ + if not new_name: + raise ValueError("Please specify a new file name.") + + new_name = new_name.strip('/') + new_path_and_query = new_name.split('?') + new_file_path = new_path_and_query[0] + if len(new_path_and_query) == 2: + new_file_sas = new_path_and_query[1] or self._query_str.strip('?') + else: + new_file_sas = self._query_str.strip('?') + + new_file_client = ShareFileClient( + f'{self.scheme}://{self.primary_hostname}', self.share_name, new_file_path, + credential=new_file_sas or self.credential, api_version=self.api_version, + _hosts=self._hosts, _configuration=self._config, _pipeline=self._pipeline, + _location_mode=self._location_mode, allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, token_intent=self.file_request_intent + ) + + kwargs.update(get_rename_smb_properties(kwargs)) + + file_http_headers = None + content_type = kwargs.pop('content_type', None) + if content_type: + file_http_headers = FileHTTPHeaders( + file_content_type=content_type + ) + + timeout = kwargs.pop('timeout', None) + overwrite = kwargs.pop('overwrite', None) + metadata = kwargs.pop('metadata', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + + source_access_conditions = get_source_access_conditions(kwargs.pop('source_lease', None)) + dest_access_conditions = get_dest_access_conditions(kwargs.pop('destination_lease', None)) + + try: + await new_file_client._client.file.rename( # pylint: disable=protected-access + self.url, + timeout=timeout, + replace_if_exists=overwrite, + file_http_headers=file_http_headers, + source_lease_access_conditions=source_access_conditions, + destination_lease_access_conditions=dest_access_conditions, + headers=headers, + **kwargs) + + return new_file_client + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def get_file_properties(self, **kwargs: Any) -> FileProperties: + """Returns all user-defined metadata, standard HTTP properties, and + system properties for the file. + + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: FileProperties + :rtype: ~azure.storage.fileshare.FileProperties + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + file_props = cast(FileProperties, await self._client.file.get_properties( + sharesnapshot=self.snapshot, + lease_access_conditions=access_conditions, + timeout=timeout, + cls=deserialize_file_properties, + **kwargs + )) + except HttpResponseError as error: + process_storage_error(error) + file_props.name = self.file_name + file_props.share = self.share_name + file_props.snapshot = self.snapshot + file_props.path = "/".join(self.file_path) + return file_props + + @distributed_trace_async + async def set_http_headers( + self, content_settings: "ContentSettings", + file_attributes: Optional[Union[str, "NTFSAttributes"]] = None, + file_creation_time: Optional[Union[str, datetime]] = None, + file_last_write_time: Optional[Union[str, datetime]] = None, + file_permission: Optional[str] = None, + permission_key: Optional[str] = None, + **kwargs: Any + ) -> Dict[str, Any]: + """Sets HTTP headers on the file. + + :param ~azure.storage.fileshare.ContentSettings content_settings: + ContentSettings object used to set file properties. Used to set content type, encoding, + language, disposition, md5, and cache control. + :param file_attributes: + The file system attributes for files and directories. + If not set, indicates preservation of existing values. + Here is an example for when the var type is str: 'Temporary|Archive' + :type file_attributes: str or ~azure.storage.fileshare.NTFSAttributes or None + :param file_creation_time: Creation time for the file + :type file_creation_time: str or ~datetime.datetime or None + :param file_last_write_time: Last write time for the file + :type file_last_write_time: str or ~datetime.datetime or None + :param file_permission: If specified the permission (security + descriptor) shall be set for the directory/file. This header can be + used if Permission size is <= 8KB, else x-ms-file-permission-key + header shall be used. Default value: Inherit. If SDDL is specified as + input, it must have owner, group and dacl. Note: Only one of the + x-ms-file-permission or x-ms-file-permission-key should be specified. + :type file_permission: str + :param permission_key: Key of the permission to be set for the + directory/file. Note: Only one of the x-ms-file-permission or + x-ms-file-permission-key should be specified. + :type permission_key: str + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :keyword file_change_time: + Change time for the file. If not specified, change time will be set to the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_change_time: str or ~datetime.datetime + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str + :keyword str owner: + NFS only. The owner of the file. + :keyword str group: + NFS only. The owning group of the file. + :keyword str file_mode: + NFS only. The file mode of the file. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + file_content_length = kwargs.pop("size", None) + file_http_headers = FileHTTPHeaders( + file_cache_control=content_settings.cache_control, + file_content_type=content_settings.content_type, + file_content_md5=bytearray(content_settings.content_md5) if content_settings.content_md5 else None, + file_content_encoding=content_settings.content_encoding, + file_content_language=content_settings.content_language, + file_content_disposition=content_settings.content_disposition, + ) + file_permission = _get_file_permission(file_permission, permission_key, None) + file_change_time = kwargs.pop('file_change_time', None) + try: + return cast(Dict[str, Any], await self._client.file.set_http_headers( + file_content_length=file_content_length, + file_http_headers=file_http_headers, + file_attributes=str(file_attributes) if file_attributes is not None else file_attributes, + file_creation_time=_datetime_to_str(file_creation_time), + file_last_write_time=_datetime_to_str(file_last_write_time), + file_change_time=_datetime_to_str(file_change_time), + file_permission=file_permission, + file_permission_key=permission_key, + lease_access_conditions=access_conditions, + timeout=timeout, + cls=return_response_headers, + **kwargs + )) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def set_file_metadata(self, metadata: Optional[Dict[str, Any]] = None, **kwargs: Any) -> Dict[str, Any]: + """Sets user-defined metadata for the specified file as one or more + name-value pairs. + + Each call to this operation replaces all existing metadata + attached to the file. To remove all metadata from the file, + call this operation with no metadata dict. + + :param metadata: + Name-value pairs associated with the file as metadata. + :type metadata: dict[str, str] + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + headers = kwargs.pop("headers", {}) + headers.update(add_metadata_headers(metadata)) + try: + return cast(Dict[str, Any], await self._client.file.set_metadata( + metadata=metadata, lease_access_conditions=access_conditions, + timeout=timeout, cls=return_response_headers, headers=headers, **kwargs + )) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def upload_range( + self, data: bytes, + offset: int, + length: int, + **kwargs: Any + ) -> Dict[str, Any]: + """Upload a range of bytes to a file. + + :param bytes data: + The data to upload. + :param int offset: + Start of byte range to use for uploading a section of the file. + The range can be up to 4 MB in size. + :param int length: + Number of bytes to use for uploading a section of the file. + The range can be up to 4 MB in size. + :keyword bool validate_content: + If true, calculates an MD5 hash of the page content. The storage + service checks the hash of the content that has arrived + with the hash that was sent. This is primarily valuable for detecting + bitflips on the wire if using http instead of https as https (the default) + will already validate. Note that this MD5 hash is not stored with the + file. + :keyword file_last_write_mode: + If the file last write time should be preserved or overwritten. Possible values + are "preserve" or "now". If not specified, file last write time will be changed to + the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_last_write_mode: Literal["preserve", "now"] + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword str encoding: + Defaults to UTF-8. + :returns: File-updated property dict (Etag and last modified). + :rtype: Dict[str, Any] + """ + validate_content = kwargs.pop('validate_content', False) + timeout = kwargs.pop('timeout', None) + encoding = kwargs.pop('encoding', 'UTF-8') + file_last_write_mode = kwargs.pop('file_last_write_mode', None) + if isinstance(data, str): + data = data.encode(encoding) + end_range = offset + length - 1 # Reformat to an inclusive range index + content_range = f'bytes={offset}-{end_range}' + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + try: + return cast(Dict[str, Any], await self._client.file.upload_range( + range=content_range, + content_length=length, + optionalbody=data, + timeout=timeout, + validate_content=validate_content, + file_last_written_mode=file_last_write_mode, + lease_access_conditions=access_conditions, + cls=return_response_headers, + **kwargs + )) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def upload_range_from_url( + self, source_url: str, + offset: int, + length: int, + source_offset: int, + **kwargs: Any + ) -> Dict[str, Any]: + """ + Writes the bytes from one Azure File endpoint into the specified range of another Azure File endpoint. + + :param int offset: + Start of byte range to use for updating a section of the file. + The range can be up to 4 MB in size. + :param int length: + Number of bytes to use for updating a section of the file. + The range can be up to 4 MB in size. + :param str source_url: + A URL of up to 2 KB in length that specifies an Azure file or blob. + The value should be URL-encoded as it would appear in a request URI. + If the source is in another account, the source must either be public + or must be authenticated via a shared access signature. If the source + is public, no authentication is required. + Examples: + https://myaccount.file.core.windows.net/myshare/mydir/myfile + https://otheraccount.file.core.windows.net/myshare/mydir/myfile?sastoken + :param int source_offset: + This indicates the start of the range of bytes(inclusive) that has to be taken from the copy source. + The service will read the same number of bytes as the destination range (length-offset). + :keyword ~datetime.datetime source_if_modified_since: + A DateTime value. Azure expects the date value passed in to be UTC. + If timezone is included, any non-UTC datetimes will be converted to UTC. + If a date is passed in without timezone info, it is assumed to be UTC. + Specify this conditional header to copy the blob only if the source + blob has been modified since the specified date/time. + :keyword ~datetime.datetime source_if_unmodified_since: + A DateTime value. Azure expects the date value passed in to be UTC. + If timezone is included, any non-UTC datetimes will be converted to UTC. + If a date is passed in without timezone info, it is assumed to be UTC. + Specify this conditional header to copy the blob only if the source blob + has not been modified since the specified date/time. + :keyword str source_etag: + The source ETag value, or the wildcard character (*). Used to check if the resource has changed, + and act according to the condition specified by the `match_condition` parameter. + :keyword ~azure.core.MatchConditions source_match_condition: + The source match condition to use upon the etag. + :keyword file_last_write_mode: + If the file last write time should be preserved or overwritten. Possible values + are "preserve" or "now". If not specified, file last write time will be changed to + the current date/time. + + .. versionadded:: 12.8.0 + + This parameter was introduced in API version '2021-06-08'. + + :paramtype file_last_write_mode: Literal["preserve", "now"] + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword str source_authorization: + Authenticate as a service principal using a client secret to access a source blob. Ensure "bearer " is + the prefix of the source_authorization string. + :returns: Result after writing to the specified range of the destination Azure File endpoint. + :rtype: dict[str, Any] + """ + options = _upload_range_from_url_options( + source_url=source_url, + offset=offset, + length=length, + source_offset=source_offset, + **kwargs + ) + try: + return cast(Dict[str, Any], await self._client.file.upload_range_from_url(**options)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def get_ranges( + self, offset: Optional[int] = None, + length: Optional[int] = None, + **kwargs: Any + ) -> List[Dict[str, int]]: + """Returns the list of valid page ranges for a file or snapshot + of a file. + + :param int offset: + Specifies the start offset of bytes over which to get ranges. + :param int length: + Number of bytes to use over which to get ranges. + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: + A list of valid ranges. + :rtype: List[dict[str, int]] + """ + options = _get_ranges_options( + snapshot=self.snapshot, + offset=offset, + length=length, + **kwargs) + try: + ranges = await self._client.file.get_range_list(**options) + except HttpResponseError as error: + process_storage_error(error) + return [{'start': file_range.start, 'end': file_range.end} for file_range in ranges.ranges] + + @distributed_trace_async + async def get_ranges_diff( + self, previous_sharesnapshot: Union[str, Dict[str, Any]], + offset: Optional[int] = None, + length: Optional[int] = None, + *, + include_renames: Optional[bool] = None, + **kwargs: Any + ) -> Tuple[List[Dict[str, int]], List[Dict[str, int]]]: + """Returns the list of valid page ranges for a file or snapshot + of a file. + + .. versionadded:: 12.6.0 + + :param int offset: + Specifies the start offset of bytes over which to get ranges. + :param int length: + Number of bytes to use over which to get ranges. + :param str previous_sharesnapshot: + The snapshot diff parameter that contains an opaque DateTime value that + specifies a previous file snapshot to be compared + against a more recent snapshot or the current file. + :keyword Optional[bool] include_renames: + Only valid if previous_sharesnapshot parameter is provided. Specifies whether the changed ranges for + a file that has been renamed or moved between the target snapshot (or live file) and the previous + snapshot should be listed. If set to True, the valid changed ranges for the file will be returned. + If set to False, the operation will result in a 409 (Conflict) response. + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: + A tuple of two lists of file ranges as dictionaries with 'start' and 'end' keys. + The first element are filled file ranges, the 2nd element is cleared file ranges. + :rtype: tuple[list[dict[str, int]], list[dict[str, int]]] + """ + options = _get_ranges_options( + snapshot=self.snapshot, + offset=offset, + length=length, + previous_sharesnapshot=previous_sharesnapshot, + support_rename=include_renames, + **kwargs) + try: + ranges = await self._client.file.get_range_list(**options) + except HttpResponseError as error: + process_storage_error(error) + return get_file_ranges_result(ranges) + + @distributed_trace_async + async def clear_range(self, offset: int, length: int, **kwargs: Any) -> Dict[str, Any]: + """Clears the specified range and releases the space used in storage for + that range. + + :param int offset: + Start of byte range to use for clearing a section of the file. + The range can be up to 4 MB in size. + :param int length: + Number of bytes to use for clearing a section of the file. + The range can be up to 4 MB in size. + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (Etag and last modified). + :rtype: Dict[str, Any] + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + + if offset is None or offset % 512 != 0: + raise ValueError("offset must be an integer that aligns with 512 bytes file size") + if length is None or length % 512 != 0: + raise ValueError("length must be an integer that aligns with 512 bytes file size") + end_range = length + offset - 1 # Reformat to an inclusive range index + content_range = f"bytes={offset}-{end_range}" + try: + return cast(Dict[str, Any], await self._client.file.upload_range( + timeout=timeout, + cls=return_response_headers, + content_length=0, + optionalbody=None, + file_range_write="clear", + range=content_range, + lease_access_conditions=access_conditions, + **kwargs + )) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def resize_file(self, size: int, **kwargs: Any) -> Dict[str, Any]: + """Resizes a file to the specified size. + + :param int size: + Size to resize file to (in bytes) + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.1.0 + + :paramtype lease: ~azure.storage.fileshare.aio.ShareLeaseClient or str + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (Etag and last modified). + :rtype: Dict[str, Any] + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + return cast(Dict[str, Any], await self._client.file.set_http_headers( + file_content_length=size, + file_attributes=None, + file_creation_time=None, + file_last_write_time=None, + file_permission="preserve", + lease_access_conditions=access_conditions, + cls=return_response_headers, + timeout=timeout, + **kwargs + )) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def list_handles(self, **kwargs: Any) -> AsyncItemPaged[Handle]: + """Lists handles for file. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: An auto-paging iterable of Handle + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.storage.fileshare.Handle] + """ + timeout = kwargs.pop('timeout', None) + results_per_page = kwargs.pop("results_per_page", None) + command = functools.partial( + self._client.file.list_handles, + sharesnapshot=self.snapshot, + timeout=timeout, + **kwargs) + return AsyncItemPaged( + command, results_per_page=results_per_page, + page_iterator_class=HandlesPaged) + + @distributed_trace_async + async def close_handle(self, handle: Union[str, Handle], **kwargs: Any) -> Dict[str, int]: + """Close an open file handle. + + :param handle: + A specific handle to close. + :type handle: str or ~azure.storage.fileshare.Handle + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: + The number of handles closed (this may be 0 if the specified handle was not found) + and the number of handles failed to close in a dict. + :rtype: dict[str, int] + """ + if isinstance(handle, Handle): + handle_id = handle.id + else: + handle_id = handle + if handle_id == '*': + raise ValueError("Handle ID '*' is not supported. Use 'close_all_handles' instead.") + try: + response = await self._client.file.force_close_handles( + handle_id, + marker=None, + sharesnapshot=self.snapshot, + cls=return_response_headers, + **kwargs + ) + return { + 'closed_handles_count': response.get('number_of_handles_closed', 0), + 'failed_handles_count': response.get('number_of_handles_failed', 0) + } + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def close_all_handles(self, **kwargs: Any) -> Dict[str, int]: + """Close any open file handles. + + This operation will block until the service has closed all open handles. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: + The number of handles closed (this may be 0 if the specified handle was not found) + and the number of handles failed to close in a dict. + :rtype: dict[str, int] + """ + timeout = kwargs.pop('timeout', None) + start_time = time.time() + + try_close = True + continuation_token = None + total_closed = 0 + total_failed = 0 + while try_close: + try: + response = await self._client.file.force_close_handles( + handle_id='*', + timeout=timeout, + marker=continuation_token, + sharesnapshot=self.snapshot, + cls=return_response_headers, + **kwargs + ) + except HttpResponseError as error: + process_storage_error(error) + continuation_token = response.get('marker') + try_close = bool(continuation_token) + total_closed += response.get('number_of_handles_closed', 0) + total_failed += response.get('number_of_handles_failed', 0) + if timeout: + timeout = max(0, timeout - (time.time() - start_time)) + return { + 'closed_handles_count': total_closed, + 'failed_handles_count': total_failed + } + + @distributed_trace_async + async def create_hardlink( + self, target: str, + *, + lease: Optional[Union[ShareLeaseClient, str]] = None, + timeout: Optional[int] = None, + **kwargs: Any + ) -> Dict[str, Any]: + """NFS only. Creates a hard link to the file specified by path. + + :param str target: + Specifies the path of the target file to which the link will be created, up to 2 KiB in length. + It should be the full path of the target starting from the root. The target file must be in the + same share and the same storage account. + :keyword lease: + Required if the file has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + :paramtype lease: ~azure.storage.fileshare.ShareLeaseClient or str or None + :keyword Optional[int] timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: File-updated property dict (ETag and last modified). + :rtype: dict[str, Any] + """ + try: + return cast(Dict[str, Any], await self._client.file.create_hard_link( + target_file=target, + lease_access_conditions=lease, + timeout=timeout, + cls=return_response_headers, + **kwargs + )) + except HttpResponseError as error: + process_storage_error(error) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_lease_async.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_lease_async.py new file mode 100644 index 00000000..70d6a392 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_lease_async.py @@ -0,0 +1,249 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=docstring-keyword-should-match-keyword-only + +import uuid + +from typing import Union, Optional, Any, TYPE_CHECKING + +from azure.core.exceptions import HttpResponseError +from azure.core.tracing.decorator_async import distributed_trace_async + +from .._shared.response_handlers import return_response_headers, process_storage_error +from .._generated.aio.operations import FileOperations, ShareOperations + +if TYPE_CHECKING: + from azure.storage.fileshare.aio import ShareClient, ShareFileClient + + +class ShareLeaseClient: # pylint: disable=client-accepts-api-version-keyword + """Creates a new ShareLeaseClient. + + This client provides lease operations on a ShareClient or ShareFileClient. + + :ivar str id: + The ID of the lease currently being maintained. This will be `None` if no + lease has yet been acquired. + :ivar str etag: + The ETag of the lease currently being maintained. This will be `None` if no + lease has yet been acquired or modified. + :ivar ~datetime.datetime last_modified: + The last modified timestamp of the lease currently being maintained. + This will be `None` if no lease has yet been acquired or modified. + + :param client: + The client of the file or share to lease. + :type client: ~azure.storage.fileshare.ShareFileClient or + ~azure.storage.fileshare.ShareClient + :param str lease_id: + A string representing the lease ID of an existing lease. This value does not + need to be specified in order to acquire a new lease, or break one. + """ + def __init__( # pylint: disable=missing-client-constructor-parameter-credential, missing-client-constructor-parameter-kwargs + self, client: Union["ShareFileClient", "ShareClient"], + lease_id: Optional[str] = None + ) -> None: + self.id = lease_id or str(uuid.uuid4()) + self.last_modified = None + self.etag = None + if hasattr(client, 'file_name'): + self._client = client._client.file # type: ignore + self._snapshot = None + elif hasattr(client, 'share_name'): + self._client = client._client.share + self._snapshot = client.snapshot + else: + raise TypeError("Lease must use ShareFileClient or ShareClient.") + + async def __aenter__(self): + return self + + async def __aexit__(self, *args: Any): + await self.release() + + @distributed_trace_async + async def acquire(self, **kwargs: Any) -> None: + """Requests a new lease. This operation establishes and manages a lock on a + file or share for write and delete operations. If the file or share does not have an active lease, + the File or Share service creates a lease on the file or share. If the file has an active lease, + you can only request a new lease using the active lease ID. + + + If the file or share does not have an active lease, the File or Share service creates a + lease on the file and returns a new lease ID. + + :keyword int lease_duration: + Specifies the duration of the lease, in seconds, or negative one + (-1) for a lease that never expires. File leases never expire. A non-infinite share lease can be + between 15 and 60 seconds. A share lease duration cannot be changed + using renew or change. Default is -1 (infinite share lease). + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + """ + try: + lease_duration = kwargs.pop('lease_duration', -1) + if self._snapshot: + kwargs['sharesnapshot'] = self._snapshot + response = await self._client.acquire_lease( + timeout=kwargs.pop('timeout', None), + duration=lease_duration, + proposed_lease_id=self.id, + cls=return_response_headers, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + self.id = response.get('lease_id') + self.last_modified = response.get('last_modified') + self.etag = response.get('etag') + + @distributed_trace_async + async def renew(self, **kwargs: Any) -> None: + """Renews the share lease. + + The share lease can be renewed if the lease ID specified in the + lease client matches that associated with the share. Note that + the lease may be renewed even if it has expired as long as the share + has not been leased again since the expiration of that lease. When you + renew a lease, the lease duration clock resets. + + .. versionadded:: 12.6.0 + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :return: None + """ + if isinstance(self._client, FileOperations): + raise TypeError("Lease renewal operations are only valid for ShareClient.") + try: + response = await self._client.renew_lease( + lease_id=self.id, + timeout=kwargs.pop('timeout', None), + sharesnapshot=self._snapshot, + cls=return_response_headers, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + self.etag = response.get('etag') + self.id = response.get('lease_id') + self.last_modified = response.get('last_modified') + + @distributed_trace_async + async def release(self, **kwargs: Any) -> None: + """Releases the lease. The lease may be released if the lease ID specified on the request matches + that associated with the share or file. Releasing the lease allows another client to immediately acquire + the lease for the share or file as soon as the release is complete. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :return: None + """ + try: + if self._snapshot: + kwargs['sharesnapshot'] = self._snapshot + response = await self._client.release_lease( + lease_id=self.id, + timeout=kwargs.pop('timeout', None), + cls=return_response_headers, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + self.etag = response.get('etag') + self.id = response.get('lease_id') + self.last_modified = response.get('last_modified') + + @distributed_trace_async + async def change(self, proposed_lease_id: str, **kwargs: Any) -> None: + """ Changes the lease ID of an active lease. A change must include the current lease ID in x-ms-lease-id and + a new lease ID in x-ms-proposed-lease-id. + + :param str proposed_lease_id: + Proposed lease ID, in a GUID string format. The File or Share service raises an error + (Invalid request) if the proposed lease ID is not in the correct format. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :return: None + """ + try: + if self._snapshot: + kwargs['sharesnapshot'] = self._snapshot + response = await self._client.change_lease( + lease_id=self.id, + proposed_lease_id=proposed_lease_id, + timeout=kwargs.pop('timeout', None), + cls=return_response_headers, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + self.etag = response.get('etag') + self.id = response.get('lease_id') + self.last_modified = response.get('last_modified') + + @distributed_trace_async + async def break_lease(self, **kwargs: Any) -> int: + """Force breaks the lease if the file or share has an active lease. Any authorized request can break the lease; + the request is not required to specify a matching lease ID. An infinite lease breaks immediately. + + Once a lease is broken, it cannot be changed. Any authorized request can break the lease; + the request is not required to specify a matching lease ID. + When a lease is successfully broken, the response indicates the interval + in seconds until a new lease can be acquired. + + :keyword int lease_break_period: + This is the proposed duration of seconds that the share lease + should continue before it is broken, between 0 and 60 seconds. This + break period is only used if it is shorter than the time remaining + on the share lease. If longer, the time remaining on the share lease is used. + A new share lease will not be available before the break period has + expired, but the share lease may be held for longer than the break + period. If this header does not appear with a break + operation, a fixed-duration share lease breaks after the remaining share lease + period elapses, and an infinite share lease breaks immediately. + + .. versionadded:: 12.5.0 + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :return: Approximate time remaining in the lease period, in seconds. + :rtype: int + """ + try: + lease_break_period = kwargs.pop('lease_break_period', None) + if self._snapshot: + kwargs['sharesnapshot'] = self._snapshot + if isinstance(self._client, ShareOperations): + kwargs['break_period'] = lease_break_period + if isinstance(self._client, FileOperations) and lease_break_period: + raise TypeError("Setting a lease break period is only applicable to Share leases.") + + response = await self._client.break_lease( + timeout=kwargs.pop('timeout', None), + cls=return_response_headers, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + return response.get('lease_time') # type: ignore diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_models.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_models.py new file mode 100644 index 00000000..dd7335bb --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_models.py @@ -0,0 +1,208 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=too-few-public-methods + +from typing import ( + Any, Callable, Dict, List, Optional +) + +from azure.core.async_paging import AsyncPageIterator +from azure.core.exceptions import HttpResponseError + +from .._shared.response_handlers import return_context_and_deserialized, process_storage_error +from .._generated.models import DirectoryItem +from .._models import Handle, ShareProperties, DirectoryProperties, FileProperties + + +def _wrap_item(item): + if isinstance(item, DirectoryItem): + return {'name': item.name, 'is_directory': True} + return {'name': item.name, 'size': item.properties.content_length, 'is_directory': False} + + +class SharePropertiesPaged(AsyncPageIterator): + """An iterable of Share properties. + + :param Callable command: Function to retrieve the next page of items. + :param Optional[str] prefix: Filters the results to return only shares whose names + begin with the specified prefix. + :param Optional[int] results_per_page: The maximum number of share names to retrieve per + call. + :param Optional[str] continuation_token: An opaque continuation token. + """ + + service_endpoint: Optional[str] = None + """The service URL.""" + prefix: Optional[str] = None + """A filename prefix being used to filter the list.""" + marker: Optional[str] = None + """The continuation token of the current page of results.""" + results_per_page: Optional[int] = None + """The maximum number of results to retrieve per API call.""" + location_mode: Optional[str] = None + """The location mode being used to list results. The available + options include "primary" and "secondary".""" + current_page: List[ShareProperties] + """The current page of listed results.""" + + def __init__( + self, command: Callable, + prefix: Optional[str] = None, + results_per_page: Optional[int] = None, + continuation_token: Optional[str] = None + ) -> None: + super(SharePropertiesPaged, self).__init__( + get_next=self._get_next_cb, + extract_data=self._extract_data_cb, + continuation_token=continuation_token or "" + ) + self._command = command + self.service_endpoint = None + self.prefix = prefix + self.marker = None + self.results_per_page = results_per_page + self.location_mode = None + self.current_page = [] + + async def _get_next_cb(self, continuation_token): + try: + return await self._command( + marker=continuation_token or None, + maxresults=self.results_per_page, + prefix=self.prefix, + cls=return_context_and_deserialized, + use_location=self.location_mode) + except HttpResponseError as error: + process_storage_error(error) + + async def _extract_data_cb(self, get_next_return): + self.location_mode, self._response = get_next_return + self.service_endpoint = self._response.service_endpoint + self.prefix = self._response.prefix + self.marker = self._response.marker + self.results_per_page = self._response.max_results + self.current_page = [ShareProperties._from_generated(i) for i in self._response.share_items] # pylint: disable=protected-access + return self._response.next_marker or None, self.current_page + + +class HandlesPaged(AsyncPageIterator): + """An iterable of Handles. + + :param Callable command: Function to retrieve the next page of items. + :param Optional[int] results_per_page: The maximum number of share names to retrieve per call. + :param Optional[str] continuation_token: An opaque continuation token to retrieve the next page of results. + """ + + marker: Optional[str] = None + """The continuation token of the current page of results.""" + results_per_page: Optional[int] = None + """The maximum number of results retrieved per API call.""" + location_mode: Optional[str] = None + """The location mode being used to list results. + The available options include "primary" and "secondary".""" + current_page: List[Handle] + """The current page of listed results.""" + + def __init__( + self, command: Callable, + results_per_page: Optional[int] = None, + continuation_token: Optional[str] = None + ) -> None: + super(HandlesPaged, self).__init__( + get_next=self._get_next_cb, + extract_data=self._extract_data_cb, + continuation_token=continuation_token or "" + ) + self._command = command + self.marker = None + self.results_per_page = results_per_page + self.location_mode = None + self.current_page = [] + + async def _get_next_cb(self, continuation_token): + try: + return await self._command( + marker=continuation_token or None, + maxresults=self.results_per_page, + cls=return_context_and_deserialized, + use_location=self.location_mode) + except HttpResponseError as error: + process_storage_error(error) + + async def _extract_data_cb(self, get_next_return): + self.location_mode, self._response = get_next_return + self.current_page = [Handle._from_generated(h) for h in self._response.handle_list] # pylint: disable=protected-access + return self._response.next_marker or None, self.current_page + + +class DirectoryPropertiesPaged(AsyncPageIterator): + """An iterable for the contents of a directory. + + This iterable will yield dicts for the contents of the directory. The dicts + will have the keys 'name' (str) and 'is_directory' (bool). + Items that are files (is_directory=False) will have an additional 'content_length' key. + + :param Callable command: Function to retrieve the next page of items. + :param Optional[str] prefix: Filters the results to return only directories whose names + begin with the specified prefix. + :param Optional[int] results_per_page: The maximum number of share names to retrieve per call. + :param Optional[str] continuation_token: An opaque continuation token. + """ + + service_endpoint: Optional[str] = None + """The service URL.""" + prefix: Optional[str] = None + """A file name prefix being used to filter the list.""" + marker: Optional[str] = None + """The continuation token of the current page of results.""" + results_per_page: Optional[int] = None + """The maximum number of results retrieved per API call.""" + continuation_token: Optional[str] = None + """The continuation token to retrieve the next page of results.""" + location_mode: Optional[str] = None + """The location mode being used to list results. The available options include "primary" and "secondary".""" + current_page: List[Dict[str, Any]] + """The current page of listed results.""" + + def __init__( + self, command: Callable, + prefix: Optional[str] = None, + results_per_page: Optional[int] = None, + continuation_token: Optional[str] = None + ) -> None: + super(DirectoryPropertiesPaged, self).__init__( + get_next=self._get_next_cb, + extract_data=self._extract_data_cb, + continuation_token=continuation_token or "" + ) + self._command = command + self.service_endpoint = None + self.prefix = prefix + self.marker = None + self.results_per_page = results_per_page + self.location_mode = None + self.current_page = [] + + async def _get_next_cb(self, continuation_token): + try: + return await self._command( + marker=continuation_token or None, + prefix=self.prefix, + maxresults=self.results_per_page, + cls=return_context_and_deserialized, + use_location=self.location_mode) + except HttpResponseError as error: + process_storage_error(error) + + async def _extract_data_cb(self, get_next_return): + self.location_mode, self._response = get_next_return + self.service_endpoint = self._response.service_endpoint + self.prefix = self._response.prefix + self.marker = self._response.marker + self.results_per_page = self._response.max_results + self.current_page = [DirectoryProperties._from_generated(i) for i in self._response.segment.directory_items] # pylint: disable = protected-access + self.current_page.extend([FileProperties._from_generated(i) for i in self._response.segment.file_items]) # pylint: disable = protected-access + return self._response.next_marker or None, self.current_page diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_share_client_async.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_share_client_async.py new file mode 100644 index 00000000..7f66feb9 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_share_client_async.py @@ -0,0 +1,991 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=docstring-keyword-should-match-keyword-only + +import sys +import warnings +from typing import ( + Any, cast, Dict, Literal, Optional, Union, + TYPE_CHECKING +) +from typing_extensions import Self + +from azure.core.async_paging import AsyncItemPaged +from azure.core.exceptions import HttpResponseError +from azure.core.pipeline import AsyncPipeline +from azure.core.tracing.decorator import distributed_trace +from azure.core.tracing.decorator_async import distributed_trace_async +from .._deserialize import deserialize_permission, deserialize_share_properties +from .._generated.aio import AzureFileStorage +from .._generated.models import ( + DeleteSnapshotsOptionType, + ShareStats, + SignedIdentifier +) +from .._models import ShareProtocols +from .._parser import _parse_snapshot +from .._share_client_helpers import ( + _create_permission_for_share_options, + _format_url, + _from_share_url, + _parse_url +) +from .._shared.policies_async import ExponentialRetry +from .._shared.base_client import parse_query, StorageAccountHostsMixin +from .._shared.base_client_async import AsyncStorageAccountHostsMixin, AsyncTransportWrapper, parse_connection_str +from .._shared.request_handlers import add_metadata_headers, serialize_iso +from .._shared.response_handlers import ( + process_storage_error, + return_headers_and_deserialized, + return_response_headers +) +from .._serialize import get_access_conditions, get_api_version +from ..aio._lease_async import ShareLeaseClient +from ._directory_client_async import ShareDirectoryClient +from ._file_client_async import ShareFileClient + +if TYPE_CHECKING: + from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential + from azure.core.credentials_async import AsyncTokenCredential + from .._models import AccessPolicy, DirectoryProperties, FileProperties, ShareProperties + + +class ShareClient(AsyncStorageAccountHostsMixin, StorageAccountHostsMixin): # type: ignore [misc] + """A client to interact with a specific share, although that share may not yet exist. + + For operations relating to a specific directory or file in this share, the clients for + those entities can also be retrieved using the :func:`get_directory_client` and :func:`get_file_client` functions. + + :param str account_url: + The URI to the storage account. In order to create a client given the full URI to the share, + use the :func:`from_share_url` classmethod. + :param share_name: + The name of the share with which to interact. + :type share_name: str + :param str snapshot: + An optional share snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`create_snapshot`. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a TokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials_async.AsyncTokenCredential or + str or dict[str, str] or None + :keyword token_intent: + Required when using `AsyncTokenCredential` for authentication and ignored for other forms of authentication. + Specifies the intent for all requests when using `AsyncTokenCredential` authentication. Possible values are: + + backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory + ACLs are bypassed and full permissions are granted. User must also have required RBAC permission. + + :paramtype token_intent: Literal['backup'] + :keyword bool allow_trailing_dot: If true, the trailing dot will not be trimmed from the target URI. + :keyword bool allow_source_trailing_dot: If true, the trailing dot will not be trimmed from the source URI. + :keyword str api_version: + The Storage API version to use for requests. Default value is the most recent service version that is + compatible with the current SDK. Setting to an older version may result in reduced feature compatibility. + + .. versionadded:: 12.1.0 + + :keyword str secondary_hostname: + The hostname of the secondary endpoint. + :keyword int max_range_size: The maximum range size used for a file upload. Defaults to 4*1024*1024. + """ + def __init__( + self, account_url: str, + share_name: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long + *, + token_intent: Optional[Literal['backup']] = None, + **kwargs: Any + ) -> None: + kwargs['retry_policy'] = kwargs.get('retry_policy') or ExponentialRetry(**kwargs) + loop = kwargs.pop('loop', None) + if loop and sys.version_info >= (3, 8): + warnings.warn("The 'loop' parameter was deprecated from asyncio's high-level" + "APIs in Python 3.8 and is no longer supported.", DeprecationWarning) + if hasattr(credential, 'get_token') and not token_intent: + raise ValueError("'token_intent' keyword is required when 'credential' is an AsyncTokenCredential.") + parsed_url = _parse_url(account_url, share_name) + path_snapshot, sas_token = parse_query(parsed_url.query) + if not sas_token and not credential: + raise ValueError( + 'You need to provide either an account shared key or SAS token when creating a storage service.') + self.snapshot = _parse_snapshot(snapshot, path_snapshot) + self.share_name = share_name + self._query_str, credential = self._format_query_string( + sas_token=sas_token, credential=credential, share_snapshot=self.snapshot) + super(ShareClient, self).__init__( + parsed_url=parsed_url, service='file-share', credential=credential, **kwargs) + self.allow_trailing_dot = kwargs.pop('allow_trailing_dot', None) + self.allow_source_trailing_dot = kwargs.pop('allow_source_trailing_dot', None) + self.file_request_intent = token_intent + self._client = AzureFileStorage(url=self.url, base_url=self.url, pipeline=self._pipeline, + allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, + file_request_intent=self.file_request_intent) + self._client._config.version = get_api_version(kwargs) # type: ignore [assignment] + + @classmethod + def from_share_url( + cls, share_url: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """ + :param str share_url: The full URI to the share. + :param snapshot: + An optional share snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`create_snapshot`. + :type snapshot: Optional[Union[str, dict[str, Any]]] + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a AsyncTokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials_async.AsyncTokenCredential or + str or dict[str, str] or None + :returns: A share client. + :rtype: ~azure.storage.fileshare.aio.ShareClient + """ + account_url, share_name, path_snapshot = _from_share_url(share_url, snapshot) + return cls(account_url, share_name, path_snapshot, credential, **kwargs) + + def _format_url(self, hostname: str) -> str: + """Format the endpoint URL according to the current location mode hostname. + + :param str hostname: + The hostname of the current location mode. + :returns: A formatted endpoint URL including current location mode hostname. + :rtype: str + """ + return _format_url(self.scheme, hostname, self.share_name, self._query_str) + + @classmethod + def from_connection_string( + cls, conn_str: str, + share_name: str, + snapshot: Optional[Union[str, Dict[str, Any]]] = None, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """Create ShareClient from a Connection String. + + :param str conn_str: + A connection string to an Azure Storage account. + :param str share_name: The name of the share. + :param snapshot: + The optional share snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`create_snapshot`. + :type snapshot: Optional[Union[str, dict[str, Any]]] + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a AsyncTokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials_async.AsyncTokenCredential or + str or dict[str, str] or None + :returns: A share client. + :rtype: ~azure.storage.fileshare.aio.ShareClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share_async.py + :start-after: [START create_share_client_from_conn_string] + :end-before: [END create_share_client_from_conn_string] + :language: python + :dedent: 8 + :caption: Gets the share client from connection string. + """ + account_url, secondary, credential = parse_connection_str(conn_str, credential, 'file') + if 'secondary_hostname' not in kwargs: + kwargs['secondary_hostname'] = secondary + return cls( + account_url, share_name=share_name, snapshot=snapshot, credential=credential, **kwargs) + + def get_directory_client(self, directory_path: Optional[str] = None) -> ShareDirectoryClient: + """Get a client to interact with the specified directory. + The directory need not already exist. + + :param str directory_path: + Path to the specified directory. + :returns: A Directory Client. + :rtype: ~azure.storage.fileshare.aio.ShareDirectoryClient + """ + _pipeline = AsyncPipeline( + transport=AsyncTransportWrapper(self._pipeline._transport), # pylint: disable=protected-access + policies=self._pipeline._impl_policies # type: ignore [arg-type] # pylint: disable=protected-access + ) + + return ShareDirectoryClient( + self.url, share_name=self.share_name, directory_path=directory_path or "", snapshot=self.snapshot, + credential=self.credential, api_version=self.api_version, _hosts=self._hosts, _configuration=self._config, + _pipeline=_pipeline, _location_mode=self._location_mode, allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, token_intent=self.file_request_intent) + + def get_file_client(self, file_path: str) -> ShareFileClient: + """Get a client to interact with the specified file. + The file need not already exist. + + :param str file_path: + Path to the specified file. + :returns: A File Client. + :rtype: ~azure.storage.fileshare.aio.ShareFileClient + """ + _pipeline = AsyncPipeline( + transport=AsyncTransportWrapper(self._pipeline._transport), # pylint: disable=protected-access + policies=self._pipeline._impl_policies # type: ignore [arg-type] # pylint: disable=protected-access + ) + + return ShareFileClient( + self.url, share_name=self.share_name, file_path=file_path, snapshot=self.snapshot, + credential=self.credential, api_version=self.api_version, _hosts=self._hosts, _configuration=self._config, + _pipeline=_pipeline, _location_mode=self._location_mode, allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, token_intent=self.file_request_intent) + + @distributed_trace_async + async def acquire_lease(self, **kwargs: Any) -> ShareLeaseClient: + """Requests a new lease. + + If the share does not have an active lease, the Share + Service creates a lease on the share and returns a new lease. + + .. versionadded:: 12.5.0 + + :keyword int lease_duration: + Specifies the duration of the lease, in seconds, or negative one + (-1) for a lease that never expires. A non-infinite lease can be + between 15 and 60 seconds. A lease duration cannot be changed + using renew or change. Default is -1 (infinite lease). + :keyword str lease_id: + Proposed lease ID, in a GUID string format. The Share Service + returns 400 (Invalid request) if the proposed lease ID is not + in the correct format. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: A ShareLeaseClient object. + :rtype: ~azure.storage.fileshare.ShareLeaseClient + """ + kwargs['lease_duration'] = kwargs.pop('lease_duration', -1) + lease_id = kwargs.pop('lease_id', None) + lease = ShareLeaseClient(self, lease_id=lease_id) + await lease.acquire(**kwargs) + return lease + + @distributed_trace_async + async def create_share(self, **kwargs: Any) -> Dict[str, Any]: + """Creates a new Share under the account. If a share with the + same name already exists, the operation fails. + + :keyword metadata: + Name-value pairs associated with the share as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword int quota: + The quota to be allotted. + :keyword access_tier: + Specifies the access tier of the share. + Possible values: 'TransactionOptimized', 'Hot', 'Cool', 'Premium' + :paramtype access_tier: str or ~azure.storage.fileshare.models.ShareAccessTier + + .. versionadded:: 12.4.0 + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword protocols: + Protocols to enable on the share. Only one protocol can be enabled on the share. + :paramtype protocols: str or ~azure.storage.fileshare.ShareProtocols + :keyword root_squash: + Root squash to set on the share. + Only valid for NFS shares. Possible values include: 'NoRootSquash', 'RootSquash', 'AllSquash'. + :paramtype root_squash: str or ~azure.storage.fileshare.ShareRootSquash + :keyword bool paid_bursting_enabled: This property enables paid bursting. + :keyword int paid_bursting_bandwidth_mibps: The maximum throughput the file share can support in MiB/s. + :keyword int paid_bursting_iops: The maximum IOPS the file share can support. + :keyword int provisioned_iops: The provisioned IOPS of the share, stored on the share object. + :keyword int provisioned_bandwidth_mibps: The provisioned throughput of the share, stored on the share object. + :returns: Share-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share_async.py + :start-after: [START create_share] + :end-before: [END create_share] + :language: python + :dedent: 12 + :caption: Creates a file share. + """ + metadata = kwargs.pop('metadata', None) + quota = kwargs.pop('quota', None) + access_tier = kwargs.pop('access_tier', None) + timeout = kwargs.pop('timeout', None) + root_squash = kwargs.pop('root_squash', None) + protocols = kwargs.pop('protocols', None) + paid_bursting_bandwidth_mibps = kwargs.pop('paid_bursting_bandwidth_mibps', None) + paid_bursting_iops = kwargs.pop('paid_bursting_iops', None) + share_provisioned_iops = kwargs.pop('provisioned_iops', None) + share_provisioned_bandwidth_mibps = kwargs.pop('provisioned_bandwidth_mibps', None) + if protocols and protocols not in ['NFS', 'SMB', ShareProtocols.SMB, ShareProtocols.NFS]: + raise ValueError("The enabled protocol must be set to either SMB or NFS.") + if root_squash and protocols not in ['NFS', ShareProtocols.NFS]: + raise ValueError("The 'root_squash' keyword can only be used on NFS enabled shares.") + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + + try: + return cast(Dict[str, Any], await self._client.share.create( + timeout=timeout, + metadata=metadata, + quota=quota, + access_tier=access_tier, + root_squash=root_squash, + enabled_protocols=protocols, + paid_bursting_max_bandwidth_mibps=paid_bursting_bandwidth_mibps, + paid_bursting_max_iops=paid_bursting_iops, + share_provisioned_iops=share_provisioned_iops, + share_provisioned_bandwidth_mibps=share_provisioned_bandwidth_mibps, + cls=return_response_headers, + headers=headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def create_snapshot(self, **kwargs: Any) -> Dict[str, Any]: + """Creates a snapshot of the share. + + A snapshot is a read-only version of a share that's taken at a point in time. + It can be read, copied, or deleted, but not modified. Snapshots provide a way + to back up a share as it appears at a moment in time. + + A snapshot of a share has the same name as the base share from which the snapshot + is taken, with a DateTime value appended to indicate the time at which the + snapshot was taken. + + :keyword metadata: + Name-value pairs associated with the share as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: Share-updated property dict (Snapshot ID, Etag, and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share_async.py + :start-after: [START create_share_snapshot] + :end-before: [END create_share_snapshot] + :language: python + :dedent: 16 + :caption: Creates a snapshot of the file share. + """ + metadata = kwargs.pop('metadata', None) + timeout = kwargs.pop('timeout', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + try: + return cast(Dict[str, Any], await self._client.share.create_snapshot( + timeout=timeout, + cls=return_response_headers, + headers=headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def delete_share( + self, delete_snapshots: Optional[Union[bool, Literal['include', 'include-leased']]] = False, + **kwargs: Any + ) -> None: + """Marks the specified share for deletion. The share is + later deleted during garbage collection. + + :param delete_snapshots: + Indicates if snapshots are to be deleted. If "True" or enum "include", snapshots will + be deleted (but not include leased). To include leased snapshots, specify the "include-leased" + enum. + :type delete_snapshots: + Optional[Union[bool, Literal['include', 'include-leased']]] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share_async.py + :start-after: [START delete_share] + :end-before: [END delete_share] + :language: python + :dedent: 16 + :caption: Deletes the share and any snapshots. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + delete_include = None + if isinstance(delete_snapshots, bool) and delete_snapshots: + delete_include = DeleteSnapshotsOptionType.INCLUDE + else: + if delete_snapshots == 'include': + delete_include = DeleteSnapshotsOptionType.INCLUDE + elif delete_snapshots == 'include-leased': + delete_include = DeleteSnapshotsOptionType.INCLUDE_LEASED + try: + await self._client.share.delete( + timeout=timeout, + sharesnapshot=self.snapshot, + delete_snapshots=delete_include, + lease_access_conditions=access_conditions, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def get_share_properties(self, **kwargs: Any) -> "ShareProperties": + """Returns all user-defined metadata and system properties for the + specified share. The data returned does not include the shares's + list of files or directories. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + :returns: The share properties. + :rtype: ~azure.storage.fileshare.ShareProperties + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_hello_world_async.py + :start-after: [START get_share_properties] + :end-before: [END get_share_properties] + :language: python + :dedent: 16 + :caption: Gets the share properties. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + props = cast("ShareProperties", await self._client.share.get_properties( + timeout=timeout, + sharesnapshot=self.snapshot, + cls=deserialize_share_properties, + lease_access_conditions=access_conditions, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + props.name = self.share_name + props.snapshot = self.snapshot + return props + + @distributed_trace_async + async def set_share_quota(self, quota: int, **kwargs: Any) -> Dict[str, Any]: + """Sets the quota for the share. + + :param int quota: + Specifies the maximum size of the share, in gigabytes. + Must be greater than 0, and less than or equal to 5TB. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + :returns: Share-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share_async.py + :start-after: [START set_share_quota] + :end-before: [END set_share_quota] + :language: python + :dedent: 16 + :caption: Sets the share quota. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + return cast(Dict[str, Any], await self._client.share.set_properties( + timeout=timeout, + quota=quota, + access_tier=None, + cls=return_response_headers, + lease_access_conditions=access_conditions, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def set_share_properties(self, **kwargs: Any) -> Dict[str, Any]: + """Sets the share properties. + + .. versionadded:: 12.3.0 + + :keyword access_tier: + Specifies the access tier of the share. + Possible values: 'TransactionOptimized', 'Hot', 'Cool', 'Premium' + :paramtype access_tier: str or ~azure.storage.fileshare.models.ShareAccessTier + :keyword int quota: + Specifies the maximum size of the share, in gigabytes. + Must be greater than 0, and less than or equal to 5TB. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword root_squash: + Root squash to set on the share. + Only valid for NFS shares. Possible values include: 'NoRootSquash', 'RootSquash', 'AllSquash' + :paramtype root_squash: str or ~azure.storage.fileshare.ShareRootSquash + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + :keyword bool paid_bursting_enabled: This property enables paid bursting. + :keyword int paid_bursting_bandwidth_mibps: The maximum throughput the file share can support in MiB/s. + :keyword int paid_bursting_iops: The maximum IOPS the file share can support. + :keyword int provisioned_iops: The provisioned IOPS of the share, stored on the share object. + :keyword int provisioned_bandwidth_mibps: The provisioned throughput of the share, stored on the share object. + :returns: Share-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share_async.py + :start-after: [START set_share_properties] + :end-before: [END set_share_properties] + :language: python + :dedent: 16 + :caption: Sets the share properties. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + access_tier = kwargs.pop('access_tier', None) + quota = kwargs.pop('quota', None) + root_squash = kwargs.pop('root_squash', None) + paid_bursting_bandwidth_mibps = kwargs.pop('paid_bursting_bandwidth_mibps', None) + paid_bursting_iops = kwargs.pop('paid_bursting_iops', None) + share_provisioned_iops = kwargs.pop('provisioned_iops', None) + share_provisioned_bandwidth_mibps = kwargs.pop('provisioned_bandwidth_mibps', None) + if all(parameter is None for parameter in [access_tier, quota, root_squash]): + raise ValueError("set_share_properties should be called with at least one parameter.") + try: + return cast(Dict[str, Any], await self._client.share.set_properties( + timeout=timeout, + quota=quota, + access_tier=access_tier, + root_squash=root_squash, + lease_access_conditions=access_conditions, + paid_bursting_max_bandwidth_mibps=paid_bursting_bandwidth_mibps, + paid_bursting_max_iops=paid_bursting_iops, + share_provisioned_iops=share_provisioned_iops, + share_provisioned_bandwidth_mibps=share_provisioned_bandwidth_mibps, + cls=return_response_headers, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def set_share_metadata(self, metadata: Dict[str, str], **kwargs: Any) -> Dict[str, Any]: + """Sets the metadata for the share. + + Each call to this operation replaces all existing metadata + attached to the share. To remove all metadata from the share, + call this operation with no metadata dict. + + :param metadata: + Name-value pairs associated with the share as metadata. + :type metadata: dict[str, str] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + :returns: Share-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share_async.py + :start-after: [START set_share_metadata] + :end-before: [END set_share_metadata] + :language: python + :dedent: 16 + :caption: Sets the share metadata. + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + headers = kwargs.pop('headers', {}) + headers.update(add_metadata_headers(metadata)) + try: + return cast(Dict[str, Any], await self._client.share.set_metadata( + timeout=timeout, + cls=return_response_headers, + headers=headers, + lease_access_conditions=access_conditions, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def get_share_access_policy(self, **kwargs: Any) -> Dict[str, Any]: + """Gets the permissions for the share. The permissions + indicate whether files in a share may be accessed publicly. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + :returns: Access policy information in a dict. + :rtype: dict[str, Any] + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + response, identifiers = await self._client.share.get_access_policy( + timeout=timeout, + cls=return_headers_and_deserialized, + lease_access_conditions=access_conditions, + **kwargs) + except HttpResponseError as error: + process_storage_error(error) + return { + 'public_access': response.get('share_public_access'), + 'signed_identifiers': identifiers or [] + } + + @distributed_trace_async + async def set_share_access_policy( + self, signed_identifiers: Dict[str, "AccessPolicy"], + **kwargs: Any + ) -> Dict[str, Any]: + """Sets the permissions for the share, or stored access + policies that may be used with Shared Access Signatures. The permissions + indicate whether files in a share may be accessed publicly. + + :param signed_identifiers: + A dictionary of access policies to associate with the share. The + dictionary may contain up to 5 elements. An empty dictionary + will clear the access policies set on the service. + :type signed_identifiers: dict[str, ~azure.storage.fileshare.AccessPolicy] + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + :returns: Share-updated property dict (Etag and last modified). + :rtype: dict[str, Any] + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + if len(signed_identifiers) > 5: + raise ValueError( + 'Too many access policies provided. The server does not support setting ' + 'more than 5 access policies on a single resource.') + identifiers = [] + for key, value in signed_identifiers.items(): + if value: + value.start = serialize_iso(value.start) + value.expiry = serialize_iso(value.expiry) + identifiers.append(SignedIdentifier(id=key, access_policy=value)) + try: + return cast(Dict[str, Any], await self._client.share.set_access_policy( + share_acl=identifiers or None, + timeout=timeout, + cls=return_response_headers, + lease_access_conditions=access_conditions, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def get_share_stats(self, **kwargs: Any) -> int: + """Gets the approximate size of the data stored on the share in bytes. + + Note that this value may not include all recently created + or recently re-sized files. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword lease: + Required if the share has an active lease. Value can be a ShareLeaseClient object + or the lease ID as a string. + + .. versionadded:: 12.5.0 + + This keyword argument was introduced in API version '2020-08-04'. + + :return: The approximate size of the data (in bytes) stored on the share. + :rtype: int + """ + access_conditions = get_access_conditions(kwargs.pop('lease', None)) + timeout = kwargs.pop('timeout', None) + try: + stats = cast(ShareStats, await self._client.share.get_statistics( + timeout=timeout, + lease_access_conditions=access_conditions, + **kwargs)) + return stats.share_usage_bytes + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def list_directories_and_files( + self, directory_name: Optional[str] = None, + name_starts_with: Optional[str] = None, + marker: Optional[str] = None, + **kwargs: Any + ) -> AsyncItemPaged[Union["DirectoryProperties", "FileProperties"]]: + """Lists the directories and files under the share. + + :param str directory_name: + Name of a directory. + :param str name_starts_with: + Filters the results to return only directories whose names + begin with the specified prefix. + :param str marker: + An opaque continuation token. This value can be retrieved from the + next_marker field of a previous generator object. If specified, + this generator will begin returning results from this point. + :keyword List[str] include: + Include this parameter to specify one or more datasets to include in the response. + Possible str values are "timestamps", "Etag", "Attributes", "PermissionKey". + + .. versionadded:: 12.6.0 + + This keyword argument was introduced in API version '2020-10-02'. + + :keyword bool include_extended_info: + If this is set to true, file id will be returned in listed results. + + .. versionadded:: 12.6.0 + + This keyword argument was introduced in API version '2020-10-02'. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: An auto-paging iterable of dict-like DirectoryProperties and FileProperties + :rtype: ~azure.core.paging.ItemPaged[Union[DirectoryProperties, FileProperties]] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_share_async.py + :start-after: [START share_list_files_in_dir] + :end-before: [END share_list_files_in_dir] + :language: python + :dedent: 16 + :caption: List directories and files in the share. + """ + timeout = kwargs.pop('timeout', None) + directory = self.get_directory_client(directory_name) + return directory.list_directories_and_files( + name_starts_with=name_starts_with, marker=marker, timeout=timeout, **kwargs) + + @distributed_trace_async + async def create_permission_for_share(self, file_permission: str, **kwargs: Any) -> Optional[str]: + """Create a permission (a security descriptor) at the share level. + + This 'permission' can be used for the files/directories in the share. + If a 'permission' already exists, it shall return the key of it, else + creates a new permission at the share level and return its key. + + :param str file_permission: + File permission, a Portable SDDL + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :returns: A file permission key + :rtype: str or None + """ + timeout = kwargs.pop('timeout', None) + options = _create_permission_for_share_options(file_permission, timeout=timeout, **kwargs) + try: + return cast(Optional[str], await self._client.share.create_permission(**options)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def get_permission_for_share(self, permission_key: str, **kwargs: Any) -> str: + """Get a permission (a security descriptor) for a given key. + + This 'permission' can be used for the files/directories in the share. + + :param str permission_key: + Key of the file permission to retrieve + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword file_permission_format: + Specifies the format in which the permission is returned. If not specified, SDDL will be the default. + :paramtype file_permission_format: Literal['sddl', 'binary'] + :returns: A file permission (a portable SDDL) + :rtype: str + """ + timeout = kwargs.pop('timeout', None) + try: + return cast(str, await self._client.share.get_permission( + file_permission_key=permission_key, + cls=deserialize_permission, + timeout=timeout, + **kwargs)) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def create_directory(self, directory_name: str, **kwargs: Any) -> ShareDirectoryClient: + """Creates a directory in the share and returns a client to interact + with the directory. + + :param str directory_name: + The name of the directory. + :keyword metadata: + Name-value pairs associated with the directory as metadata. + :paramtype metadata: Optional[dict[str, str]] + :keyword str owner: + NFS only. The owner of the directory. + :keyword str group: + NFS only. The owning group of the directory. + :keyword str file_mode: + NFS only. The file mode of the directory. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: ShareDirectoryClient + :rtype: ~azure.storage.fileshare.aio.ShareDirectoryClient + """ + directory = self.get_directory_client(directory_name) + kwargs.setdefault('merge_span', True) + await directory.create_directory(**kwargs) + return directory + + @distributed_trace_async + async def delete_directory(self, directory_name: str, **kwargs: Any) -> None: + """Marks the directory for deletion. The directory is + later deleted during garbage collection. + + :param str directory_name: + The name of the directory. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + """ + directory = self.get_directory_client(directory_name) + await directory.delete_directory(**kwargs) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_share_service_client_async.py b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_share_service_client_async.py new file mode 100644 index 00000000..bf33ac78 --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/aio/_share_service_client_async.py @@ -0,0 +1,490 @@ +# ------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See License.txt in the project root for +# license information. +# -------------------------------------------------------------------------- +# pylint: disable=docstring-keyword-should-match-keyword-only + +import functools +import sys +import warnings +from typing import ( + Union, Optional, Any, Dict, List, + TYPE_CHECKING +) +from typing_extensions import Self + +from azure.core.async_paging import AsyncItemPaged +from azure.core.exceptions import HttpResponseError +from azure.core.tracing.decorator import distributed_trace +from azure.core.tracing.decorator_async import distributed_trace_async +from azure.core.pipeline import AsyncPipeline +from .._generated.aio import AzureFileStorage +from .._generated.models import StorageServiceProperties +from .._models import CorsRule, service_properties_deserialize, ShareProperties +from .._serialize import get_api_version +from .._share_service_client_helpers import _parse_url +from .._shared.base_client import StorageAccountHostsMixin, parse_query +from .._shared.base_client_async import AsyncStorageAccountHostsMixin, AsyncTransportWrapper, parse_connection_str +from .._shared.policies_async import ExponentialRetry +from .._shared.response_handlers import process_storage_error +from ._models import SharePropertiesPaged +from ._share_client_async import ShareClient + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal + +if TYPE_CHECKING: + from azure.core.credentials import AzureNamedKeyCredential, AzureSasCredential + from azure.core.credentials_async import AsyncTokenCredential + from .._models import Metrics, ShareProtocolSettings + + +class ShareServiceClient(AsyncStorageAccountHostsMixin, StorageAccountHostsMixin): # type: ignore [misc] + """A client to interact with the File Share Service at the account level. + + This client provides operations to retrieve and configure the account properties + as well as list, create and delete shares within the account. + For operations relating to a specific share, a client for that entity + can also be retrieved using the :func:`get_share_client` function. + + :param str account_url: + The URL to the file share storage account. Any other entities included + in the URL path (e.g. share or file) will be discarded. This URL can be optionally + authenticated with a SAS token. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a AsyncTokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials_async.AsyncTokenCredential or + str or dict[str, str] or None + :keyword token_intent: + Required when using `AsyncTokenCredential` for authentication and ignored for other forms of authentication. + Specifies the intent for all requests when using `AsyncTokenCredential` authentication. Possible values are: + + backup - Specifies requests are intended for backup/admin type operations, meaning that all file/directory + ACLs are bypassed and full permissions are granted. User must also have required RBAC permission. + + :paramtype token_intent: Literal['backup'] + :keyword bool allow_trailing_dot: If true, the trailing dot will not be trimmed from the target URI. + :keyword bool allow_source_trailing_dot: If true, the trailing dot will not be trimmed from the source URI. + :keyword str api_version: + The Storage API version to use for requests. Default value is the most recent service version that is + compatible with the current SDK. Setting to an older version may result in reduced feature compatibility. + + .. versionadded:: 12.1.0 + + :keyword str secondary_hostname: + The hostname of the secondary endpoint. + :keyword int max_range_size: The maximum range size used for a file upload. Defaults to 4*1024*1024. + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_authentication_async.py + :start-after: [START create_share_service_client] + :end-before: [END create_share_service_client] + :language: python + :dedent: 8 + :caption: Create the share service client with url and credential. + """ + def __init__( + self, account_url: str, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long + *, + token_intent: Optional[Literal['backup']] = None, + **kwargs: Any + ) -> None: + kwargs['retry_policy'] = kwargs.get('retry_policy') or ExponentialRetry(**kwargs) + loop = kwargs.pop('loop', None) + if loop and sys.version_info >= (3, 8): + warnings.warn("The 'loop' parameter was deprecated from asyncio's high-level" + "APIs in Python 3.8 and is no longer supported.", DeprecationWarning) + + if hasattr(credential, 'get_token') and not token_intent: + raise ValueError("'token_intent' keyword is required when 'credential' is an AsyncTokenCredential.") + parsed_url = _parse_url(account_url=account_url) + _, sas_token = parse_query(parsed_url.query) + if not sas_token and not credential: + raise ValueError( + 'You need to provide either an account shared key or SAS token when creating a storage service.') + + self._query_str, credential = self._format_query_string(sas_token, credential) + super(ShareServiceClient, self).__init__( + parsed_url, service='file-share', credential=credential, **kwargs) + self.allow_trailing_dot = kwargs.pop('allow_trailing_dot', None) + self.allow_source_trailing_dot = kwargs.pop('allow_source_trailing_dot', None) + self.file_request_intent = token_intent + self._client = AzureFileStorage(url=self.url, base_url=self.url, pipeline=self._pipeline, + allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, + file_request_intent=self.file_request_intent) + self._client._config.version = get_api_version(kwargs) # type: ignore [assignment] + + def _format_url(self, hostname: str) -> str: + """Format the endpoint URL according to the current location mode hostname. + + :param str hostname: + The hostname of the current location mode. + :returns: A formatted endpoint URL including current location mode hostname. + :rtype: str + """ + return f"{self.scheme}://{hostname}/{self._query_str}" + + @classmethod + def from_connection_string( + cls, conn_str: str, + credential: Optional[Union[str, Dict[str, str], "AzureNamedKeyCredential", "AzureSasCredential", "AsyncTokenCredential"]] = None, # pylint: disable=line-too-long + **kwargs: Any + ) -> Self: + """Create ShareServiceClient from a Connection String. + + :param str conn_str: + A connection string to an Azure Storage account. + :param credential: + The credentials with which to authenticate. This is optional if the + account URL already has a SAS token. The value can be a SAS token string, + an instance of a AzureSasCredential or AzureNamedKeyCredential from azure.core.credentials, + an account shared access key, or an instance of a AsyncTokenCredentials class from azure.identity. + If the resource URI already contains a SAS token, this will be ignored in favor of an explicit credential + - except in the case of AzureSasCredential, where the conflicting SAS tokens will raise a ValueError. + If using an instance of AzureNamedKeyCredential, "name" should be the storage account name, and "key" + should be the storage account key. + :type credential: + ~azure.core.credentials.AzureNamedKeyCredential or + ~azure.core.credentials.AzureSasCredential or + ~azure.core.credentials_async.AsyncTokenCredential or + str or dict[str, str] or None + :returns: A File Share service client. + :rtype: ~azure.storage.fileshare.ShareServiceClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_authentication_async.py + :start-after: [START create_share_service_client_from_conn_string] + :end-before: [END create_share_service_client_from_conn_string] + :language: python + :dedent: 8 + :caption: Create the share service client with connection string. + """ + account_url, secondary, credential = parse_connection_str(conn_str, credential, 'file') + if 'secondary_hostname' not in kwargs: + kwargs['secondary_hostname'] = secondary + return cls(account_url, credential=credential, **kwargs) + + @distributed_trace_async + async def get_service_properties(self, **kwargs: Any) -> Dict[str, Any]: + """Gets the properties of a storage account's File Share service, including + Azure Storage Analytics. + + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: A dictionary containing file service properties such as + analytics logging, hour/minute metrics, cors rules, etc. + :rtype: Dict[str, Any] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_service_async.py + :start-after: [START get_service_properties] + :end-before: [END get_service_properties] + :language: python + :dedent: 12 + :caption: Get file share service properties. + """ + timeout = kwargs.pop('timeout', None) + try: + service_props = await self._client.service.get_properties(timeout=timeout, **kwargs) + return service_properties_deserialize(service_props) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace_async + async def set_service_properties( + self, hour_metrics: Optional["Metrics"] = None, + minute_metrics: Optional["Metrics"] = None, + cors: Optional[List[CorsRule]] = None, + protocol: Optional["ShareProtocolSettings"] = None, + **kwargs: Any + ) -> None: + """Sets the properties of a storage account's File Share service, including + Azure Storage Analytics. If an element (e.g. hour_metrics) is left as None, the + existing settings on the service for that functionality are preserved. + + :param hour_metrics: + The hour metrics settings provide a summary of request + statistics grouped by API in hourly aggregates for files. + :type hour_metrics: ~azure.storage.fileshare.Metrics + :param minute_metrics: + The minute metrics settings provide request statistics + for each minute for files. + :type minute_metrics: ~azure.storage.fileshare.Metrics + :param cors: + You can include up to five CorsRule elements in the + list. If an empty list is specified, all CORS rules will be deleted, + and CORS will be disabled for the service. + :type cors: list[~azure.storage.fileshare.CorsRule] + :param protocol: + Sets protocol settings + :type protocol: ~azure.storage.fileshare.ShareProtocolSettings + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_service_async.py + :start-after: [START set_service_properties] + :end-before: [END set_service_properties] + :language: python + :dedent: 8 + :caption: Sets file share service properties. + """ + timeout = kwargs.pop('timeout', None) + props = StorageServiceProperties( + hour_metrics=hour_metrics, + minute_metrics=minute_metrics, + cors=CorsRule._to_generated(cors), # pylint: disable=protected-access + protocol=protocol + ) + try: + await self._client.service.set_properties(props, timeout=timeout, **kwargs) + except HttpResponseError as error: + process_storage_error(error) + + @distributed_trace + def list_shares( + self, name_starts_with: Optional[str] = None, + include_metadata: Optional[bool] = False, + include_snapshots: Optional[bool] = False, + **kwargs: Any + ) -> AsyncItemPaged[ShareProperties]: + """Returns auto-paging iterable of dict-like ShareProperties under the specified account. + The generator will lazily follow the continuation tokens returned by + the service and stop when all shares have been returned. + + :param str name_starts_with: + Filters the results to return only shares whose names + begin with the specified name_starts_with. + :param bool include_metadata: + Specifies that share metadata be returned in the response. + :param bool include_snapshots: + Specifies that share snapshot be returned in the response. + :keyword bool include_deleted: + Specifies that deleted shares be returned in the response. + This is only for share soft delete enabled account. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :returns: An iterable (auto-paging) of ShareProperties. + :rtype: ~azure.core.async_paging.AsyncItemPaged[~azure.storage.fileshare.ShareProperties] + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_service_async.py + :start-after: [START fsc_list_shares] + :end-before: [END fsc_list_shares] + :language: python + :dedent: 16 + :caption: List shares in the file share service. + """ + timeout = kwargs.pop('timeout', None) + include = [] + include_deleted = kwargs.pop('include_deleted', None) + if include_deleted: + include.append("deleted") + if include_metadata: + include.append('metadata') + if include_snapshots: + include.append('snapshots') + + results_per_page = kwargs.pop('results_per_page', None) + command = functools.partial( + self._client.service.list_shares_segment, + include=include, + timeout=timeout, + **kwargs) + return AsyncItemPaged( + command, prefix=name_starts_with, results_per_page=results_per_page, + page_iterator_class=SharePropertiesPaged) + + @distributed_trace_async + async def create_share(self, share_name: str, **kwargs: Any) -> ShareClient: + """Creates a new share under the specified account. If the share + with the same name already exists, the operation fails. Returns a client with + which to interact with the newly created share. + + :param str share_name: The name of the share to create. + :keyword dict[str, str] metadata: + A dict with name_value pairs to associate with the + share as metadata. Example:{'Category':'test'} + :keyword int quota: + Quota in bytes. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :keyword int provisioned_iops: The provisioned IOPS of the share, stored on the share object. + :keyword int provisioned_bandwidth_mibps: The provisioned throughput of the share, stored on the share object. + :return: A ShareClient for the newly created Share. + :rtype: ~azure.storage.fileshare.aio.ShareClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_service_async.py + :start-after: [START fsc_create_shares] + :end-before: [END fsc_create_shares] + :language: python + :dedent: 12 + :caption: Create a share in the file share service. + """ + metadata = kwargs.pop('metadata', None) + quota = kwargs.pop('quota', None) + timeout = kwargs.pop('timeout', None) + provisioned_iops = kwargs.pop('provisioned_iops', None) + provisioned_bandwidth_mibps = kwargs.pop('provisioned_bandwidth_mibps', None) + share = self.get_share_client(share_name) + kwargs.setdefault('merge_span', True) + await share.create_share( + metadata=metadata, + quota=quota, + timeout=timeout, + provisioned_iops=provisioned_iops, + provisioned_bandwidth_mibps=provisioned_bandwidth_mibps, + **kwargs + ) + return share + + @distributed_trace_async + async def delete_share( + self, share_name: Union[ShareProperties, str], + delete_snapshots: Optional[bool] = False, + **kwargs: Any + ) -> None: + """Marks the specified share for deletion. The share is + later deleted during garbage collection. + + :param share_name: + The share to delete. This can either be the name of the share, + or an instance of ShareProperties. + :type share_name: str or ~azure.storage.fileshare.ShareProperties + :param bool delete_snapshots: + Indicates if snapshots are to be deleted. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :rtype: None + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_service_async.py + :start-after: [START fsc_delete_shares] + :end-before: [END fsc_delete_shares] + :language: python + :dedent: 16 + :caption: Delete a share in the file share service. + """ + timeout = kwargs.pop('timeout', None) + share = self.get_share_client(share_name) + kwargs.setdefault('merge_span', True) + await share.delete_share( + delete_snapshots=delete_snapshots, timeout=timeout, **kwargs) + + @distributed_trace_async + async def undelete_share(self, deleted_share_name: str, deleted_share_version: str, **kwargs: Any) -> ShareClient: + """Restores soft-deleted share. + + Operation will only be successful if used within the specified number of days + set in the delete retention policy. + + .. versionadded:: 12.2.0 + + This operation was introduced in API version '2019-12-12'. + + :param str deleted_share_name: + Specifies the name of the deleted share to restore. + :param str deleted_share_version: + Specifies the version of the deleted share to restore. + :keyword int timeout: + Sets the server-side timeout for the operation in seconds. For more details see + https://learn.microsoft.com/rest/api/storageservices/setting-timeouts-for-file-service-operations. + This value is not tracked or validated on the client. To configure client-side network timesouts + see `here <https://github.com/Azure/azure-sdk-for-python/tree/main/sdk/storage/azure-storage-file-share + #other-client--per-operation-configuration>`__. + :return: A ShareClient for the undeleted Share. + :rtype: ~azure.storage.fileshare.aio.ShareClient + """ + share = self.get_share_client(deleted_share_name) + try: + await share._client.share.restore(deleted_share_name=deleted_share_name, # pylint: disable=protected-access + deleted_share_version=deleted_share_version, + timeout=kwargs.pop('timeout', None), **kwargs) + return share + except HttpResponseError as error: + process_storage_error(error) + + def get_share_client( + self, share: Union[ShareProperties, str], + snapshot: Optional[Union[Dict[str, Any], str]] = None + ) -> ShareClient: + """Get a client to interact with the specified share. + The share need not already exist. + + :param share: + The share. This can either be the name of the share, + or an instance of ShareProperties. + :type share: str or ~azure.storage.fileshare.ShareProperties + :param str snapshot: + An optional share snapshot on which to operate. This can be the snapshot ID string + or the response returned from :func:`create_snapshot`. + :returns: A ShareClient. + :rtype: ~azure.storage.fileshare.aio.ShareClient + + .. admonition:: Example: + + .. literalinclude:: ../samples/file_samples_service_async.py + :start-after: [START get_share_client] + :end-before: [END get_share_client] + :language: python + :dedent: 8 + :caption: Gets the share client. + """ + if isinstance(share, ShareProperties): + share_name = share.name + else: + share_name = share + + _pipeline = AsyncPipeline( + transport=AsyncTransportWrapper(self._pipeline._transport), # pylint: disable = protected-access + policies=self._pipeline._impl_policies # type: ignore [arg-type] # pylint: disable = protected-access + ) + return ShareClient( + self.url, share_name=share_name, snapshot=snapshot, credential=self.credential, + api_version=self.api_version, _hosts=self._hosts, _configuration=self._config, + _pipeline=_pipeline, _location_mode=self._location_mode, allow_trailing_dot=self.allow_trailing_dot, + allow_source_trailing_dot=self.allow_source_trailing_dot, token_intent=self.file_request_intent) diff --git a/.venv/lib/python3.12/site-packages/azure/storage/fileshare/py.typed b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/py.typed new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/.venv/lib/python3.12/site-packages/azure/storage/fileshare/py.typed |