o
    oĎiX                     @   s  d dl m Z mZ d dlZd dlZd dlmZ d dlmZ d dlm	Z	m
Z
mZmZmZmZmZ d dlmZ zd dlmZ W n eyK   d dlmZ Y nw dd	lmZmZ dd
lmZ ddlmZ ddlmZ ddlmZ z4d dl m!Z!m"Z" d dl#m$Z$ d dl%m&Z&m'Z'm(Z(m)Z)m*Z*m+Z+ d dl,m-Z. d dl/m0Z0m1Z1 d dl2m-Z3 W n e4y   ded _5Y nw edG dd deZ6dd Z7e6j8e6_dS )    )datetime	timedeltaN)
HTTPStatus)Path)AnyCallableDictIterableOptionalTupleUnion)islice)cast   )Clientregister_client_class)implementation_registry)FileCacheMode)MissingCredentialsError   )AzureBlobPath)HttpResponseErrorResourceNotFoundError)AzureNamedKeyCredential)
BlobPrefixBlobSasPermissionsBlobServiceClientBlobPropertiesContentSettingsgenerate_blob_sas)SharedKeyCredentialPolicy)DataLakeServiceClientFilePropertiesFazurec                       s  e Zd ZdZdddddddejfdee dee dee ded ded	 d
ee	ee
f  dee	eejf  dee f fddZdedee fddZdedefddZdede	ddeeef f fddZedefddZdede	eejf defddZdedee fddZdedefd d!Z	"d;ded#edeeeef  fd$d%Z	&d<d'ed(ed)edefd*d+Z	"d=ded,ed-eddfd.d/Zd<ded0eddfd1d2Z de	eejf dedefd3d4Z!dedefd5d6Z"	7d>ded8e#defd9d:Z$  Z%S )?AzureBlobClienta  Client class for Azure Blob Storage which handles authentication with Azure for
    [`AzureBlobPath`](../azblobpath/) instances. See documentation for the
    [`__init__` method][cloudpathlib.azure.azblobclient.AzureBlobClient.__init__] for detailed
    authentication options.
    Naccount_url
credentialconnection_stringblob_service_clientr   data_lake_clientr!   file_cache_modelocal_cache_dircontent_type_methodc	           	         s  t  j|||d |du rtdd}d| _|durF|| _|du rBt|jts*|jnt	|jj
|jj}t| jjddd|d| _n|| _n|durr|| _|du rqt|jtsZ|jnt	|jj
|jj}t| jjddd|d| _nS|durtj||d| _tj||d| _n>|durd|v rt|dd|d| _t||d| _n#d|v rt||d| _t|dd|d| _nt||d| _ntd	d| _dS )
a  Class constructor. Sets up a [`BlobServiceClient`](
        https://docs.microsoft.com/en-us/python/api/azure-storage-blob/azure.storage.blob.blobserviceclient?view=azure-python).
        Supports the following authentication methods of `BlobServiceClient`.

        - Environment variable `""AZURE_STORAGE_CONNECTION_STRING"` containing connecting string
        with account credentials. See [Azure Storage SDK documentation](
        https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-python#copy-your-credentials-from-the-azure-portal).
        - Connection string via `connection_string`, authenticated either with an embedded SAS
        token or with credentials passed to `credentials`.
        - Account URL via `account_url`, authenticated either with an embedded SAS token, or with
        credentials passed to `credentials`.
        - Instantiated and already authenticated [`BlobServiceClient`](
        https://docs.microsoft.com/en-us/python/api/azure-storage-blob/azure.storage.blob.blobserviceclient?view=azure-python) or
        [`DataLakeServiceClient`](https://learn.microsoft.com/en-us/python/api/azure-storage-file-datalake/azure.storage.filedatalake.datalakeserviceclient).

        If multiple methods are used, priority order is reverse of list above (later in list takes
        priority). If no methods are used, a [`MissingCredentialsError`][cloudpathlib.exceptions.MissingCredentialsError]
        exception will be raised raised.

        Args:
            account_url (Optional[str]): The URL to the blob storage account, optionally
                authenticated with a SAS token. See documentation for [`BlobServiceClient`](
                https://docs.microsoft.com/en-us/python/api/azure-storage-blob/azure.storage.blob.blobserviceclient?view=azure-python).
            credential (Optional[Any]): Credentials with which to authenticate. Can be used with
                `account_url` or `connection_string`, but is unnecessary if the other already has
                an SAS token. See documentation for [`BlobServiceClient`](
                https://docs.microsoft.com/en-us/python/api/azure-storage-blob/azure.storage.blob.blobserviceclient?view=azure-python)
                or [`BlobServiceClient.from_connection_string`](
                https://docs.microsoft.com/en-us/python/api/azure-storage-blob/azure.storage.blob.blobserviceclient?view=azure-python#from-connection-string-conn-str--credential-none----kwargs-).
            connection_string (Optional[str]): A connection string to an Azure Storage account. See
                [Azure Storage SDK documentation](
                https://docs.microsoft.com/en-us/azure/storage/blobs/storage-quickstart-blobs-python#copy-your-credentials-from-the-azure-portal).
            blob_service_client (Optional[BlobServiceClient]): Instantiated [`BlobServiceClient`](
                https://docs.microsoft.com/en-us/python/api/azure-storage-blob/azure.storage.blob.blobserviceclient?view=azure-python).
            data_lake_client (Optional[DataLakeServiceClient]): Instantiated [`DataLakeServiceClient`](
                https://learn.microsoft.com/en-us/python/api/azure-storage-file-datalake/azure.storage.filedatalake.datalakeserviceclient).
                If None and `blob_service_client` is passed, we will create based on that.
                Otherwise, will create based on passed credential, account_url, connection_string, or AZURE_STORAGE_CONNECTION_STRING env var
            file_cache_mode (Optional[Union[str, FileCacheMode]]): How often to clear the file cache; see
                [the caching docs](https://cloudpathlib.drivendata.org/stable/caching/) for more information
                about the options in cloudpathlib.eums.FileCacheMode.
            local_cache_dir (Optional[Union[str, os.PathLike]]): Path to directory to use as cache
                for downloaded files. If None, will use a temporary directory. Default can be set with
                the `CLOUDPATHLIB_LOCAL_CACHE_DIR` environment variable.
            content_type_method (Optional[Callable]): Function to call to guess media type (mimetype) when
                writing a file to the cloud. Defaults to `mimetypes.guess_type`. Must return a tuple (content type, content encoding).
        )r+   r,   r*   NAZURE_STORAGE_CONNECTION_STRINGz.blob.z.dfs.r   )r%   r&   )conn_strr&   ziAzureBlobClient does not support anonymous instantiation. Credentials are required; see docs for options.)super__init__osgetenvr)   service_client
isinstancer&   BlobSharedKeyCredentialPolicyr   account_nameaccount_keyr!   urlreplace!DataLakeSharedKeyCredentialPolicyr   from_connection_stringr   _hns_enabled)	selfr%   r&   r'   r(   r)   r*   r+   r,   	__class__ [/home/jeff/fluffinator/venv/lib/python3.10/site-packages/cloudpathlib/azure/azblobclient.pyr0   7   s   :





zAzureBlobClient.__init__
cloud_pathreturnc              
   C   s   | j d u rAz| j }|dd| _ W | j S  ty#   | | Y S  ty@ } z|jtj	kr;| |W  Y d }~S  d }~ww | j S )Nis_hns_enabledF)
r<   r3   get_account_informationgetr   _check_hns_root_metadatar   status_coder   	FORBIDDEN)r=   rB   account_infoerrorr@   r@   rA   
_check_hns   s   

zAzureBlobClient._check_hnsc                 C   s>   | j j|jdd}| o| jdddk| _tt	| jS )N/	containerblobhdi_isfolderFtrue)
r3   get_blob_clientrO   existsget_blob_propertiesmetadatarF   r<   r   bool)r=   rB   root_dirr@   r@   rA   rG      s
   z(AzureBlobClient._check_hns_root_metadatar   r"   c                 C   sz   |  |r'| j|j}|d ur||j }|ddd id|d< |S | jj	|j|jd}|
 }|jj|d< |S )Ncontent_settingscontent_typerN   )rL   r)   get_file_system_clientrO   get_file_clientrP   get_file_propertiesrF   r3   rS   rU   rY   rZ   )r=   rB   fsc
propertiesrP   r@   r@   rA   _get_metadata   s    
zAzureBlobClient._get_metadatac                 C   s   t t| d S )Nz.part)r   str)
local_pathr@   r@   rA   _partial_filename  s   z!AzureBlobClient._partial_filenamerb   c                 C   s   | j j|j|jd}| }t|}|jjddd z'| |}|	d}|
| W d    n1 s5w   Y  || W |S    | rM|   )NrN   T)exist_okparentswb)r3   rS   rO   rP   download_blobr   parentmkdirrc   openreadintor9   rT   unlink)r=   rB   rb   rP   download_streampartial_local_pathdatar@   r@   rA   _download_file  s"   
zAzureBlobClient._download_filec                 C   s   |j sdS z| |}|dds|di ddrdW S dW S  tyT   |j }|r5|ds5|d7 }| j|j}zt|j	|d W Y dS  t
yS   Y Y d S w w )	Ndiris_directoryFrV   rQ   filerM   name_starts_with)rP   r`   rF   r   endswithr3   get_container_clientrO   next
list_blobsStopIteration)r=   rB   metaprefixcontainer_clientr@   r@   rA   _is_file_or_dir#  s.   

zAzureBlobClient._is_file_or_dirc                 C   s&   |j s| j|j S | |dv S )N)rs   rq   )rP   r3   rw   rO   rT   r~   )r=   rB   r@   r@   rA   _existsB  s   zAzureBlobClient._existsF	recursivec                 c   sV   |j s2| j D ]&}| |j |j dfV  |sq	| j| |j |j ddE d H  q	d S | j|j }|j}|rG|	dsG|d7 }| 
|ru| j|j }|j|j|d}|D ]}| |j |j  d|j |jfV  q]d S |s~|j|d}	n|j|d}	|	D ]"}
|
jd}| |j |j  d| }||st|
tndfV  qd S )NTr   rM   )pathr   rt   F)rO   r3   list_containers	CloudPathcloud_prefixname	_list_dirrw   rP   rv   rL   r)   r[   	get_pathsrr   
walk_blobsry   rstripr4   r   )r=   rB   r   rO   r}   r|   file_system_clientpathsr   blobsrP   	blob_pathblob_cloud_pathr@   r@   rA   r   I  sL   
zAzureBlobClient._list_dirTsrcdst
remove_srcc                 C   s  ||kr| j j|j|jd}|jttt 	 dd |S |rc|j
|j
u rc| |rc| j|j}| rI||j|j d|j  |S |jjddd ||j|j d|j  |S | j j|j|jd}| j j|j|jd}||j |r| | |S )NrN   )last_modified)rV   rM   T)re   rd   )r3   rS   rO   rP   set_blob_metadatadictra   r   utcnow	timestampclientrL   r)   r[   is_dirget_directory_clientrename_directoryrh   ri   r\   rename_filestart_copy_from_urlr8   _remove)r=   r   r   r   blob_clientr^   targetsourcer@   r@   rA   
_move_filez  s,     
zAzureBlobClient._move_filere   rd   c                 C   sr   |  |r6| j|j}||j}|s| rtd| |s0| |j	s0t
d|j	 d|  d S 	 d S )NzDirectory already exists: z!Parent directory does not exist (z4). To create parent directories, use `parents=True`.)rL   r)   r[   rO   r   rP   rT   FileExistsErrorr   rh   FileNotFoundErrorcreate_directory)r=   rB   re   rd   r   directory_clientr@   r@   rA   _mkdir  s   
zAzureBlobClient._mkdir
missing_okc                 C   s   |  |}|dkrG| |rt| j|j|j d S dd | j|ddD }| j|j}t	t
|d }rE|j|  t	t
|d }s5d S d S |dkr[| jj|j|jd}|  d S |sdtd	| d S )
Nrq   c                 s   s    | ]
\}}|s|j V  qd S )N)rP   ).0br   r@   r@   rA   	<genexpr>  s    
z*AzureBlobClient._remove.<locals>.<genexpr>Tr      rs   rN   zFile does not exist: )r~   rL   _hns_rmtreer)   rO   rP   r   r3   rw   tupler   delete_blobsrS   delete_blobr   )r=   rB   r   file_or_dirr   r}   batchrP   r@   r@   rA   r     s(   


zAzureBlobClient._removec           	      C   s   | j j|j|jd}i }| jd ur*| t|\}}|d ur"||d< |d ur*||d< tdi |}t|d}|j	|d|d W d    |S 1 sLw   Y  |S )NrN   rZ   content_encodingrbT)	overwriterY   r@   )
r3   rS   rO   rP   r,   ra   r   r   rj   upload_blob)	r=   rb   rB   rP   
extra_argsrZ   r   rY   ro   r@   r@   rA   _upload_file  s"   

zAzureBlobClient._upload_filec                 C   s   | j j|j|jd}|jS )NrN   )r3   rS   rO   rP   r8   )r=   rB   r   r@   r@   rA   _get_public_url  s   zAzureBlobClient._get_public_url  expire_secondsc              
   C   sN   t | jj|j|j| jjjtddt	 t
|d d}| | d| }|S )NT)read)seconds)container_name	blob_namer7   
permissionexpiry?)r   r3   r6   rO   rP   r&   r7   r   r   r   r   r   )r=   rB   r   	sas_tokenr8   r@   r@   rA   _generate_presigned_url  s   z'AzureBlobClient._generate_presigned_url)F)T)FF)r   )&__name__
__module____qualname____doc__	mimetypes
guess_typer
   ra   r   r   r   r1   PathLiker   r0   r   rW   rL   rG   r   r`   staticmethodr   rc   rp   r~   r   r	   r   r   r   r   r   r   r   intr   __classcell__r@   r@   r>   rA   r$   /   s    	 



2
$

r$   c                 C   s    |  |}||}|  dS )zStateless implementation so can be used in test suite cleanup as well.

    If hierarchical namespace is enabled, delete the directory and all its contents.
    (The non-HNS version is implemented in `_remove`, but will leave empty folders in HNS).
    N)r[   r   delete_directory)r)   rO   	directoryr   r   r@   r@   rA   r     s   

r   )9r   r   r   r1   httpr   pathlibr   typingr   r   r   r	   r
   r   r   	itertoolsr   r   ImportErrortyping_extensionsr   r   r   	cloudpathr   enumsr   
exceptionsr   
azblobpathr   azure.core.exceptionsr   r   azure.core.credentialsr   azure.storage.blobr   r   r   r   r   r   )azure.storage.blob._shared.authenticationr    r5   azure.storage.filedatalaker!   r"   1azure.storage.filedatalake._shared.authenticationr:   ModuleNotFoundErrordependencies_loadedr$   r   r   r@   r@   r@   rA   <module>   sD    $ 	   I